Blog 7 min read
Is vibe coding bad? We planted 18 bugs and sent QA in
Is vibe coding bad? We built a demo app with 18 bugs typical of AI-built apps, kept the answer key and ran QA on it. What it found, what it missed.
Is vibe coding bad? No. Vibe coding isn't bad; shipping a vibe-coded app nobody has tested is. Prompting gets you a working app fast. The risk is at the edges (unusual input, phones, timing), where nobody looked, because you didn't write the code and the AI built the path you described.
To show what those edge bugs look like and how much testing catches, we built a demo app, planted 18 bugs of the kinds AI-written code tends to make, kept the answer key, and ran our own QA against it. Vibe coding bugs aren't random. They cluster, and once you know where, you can check for them in an afternoon.
The setup
Taskpup is a small to-do app we built for this. It has a marketing site, sign-up and log-in, a task dashboard with sorting and editing, settings, a pricing page, an upgrade checkout using a test card, and a contact form. It looks like the kind of thing people ship from Lovable or Bolt in a weekend.
We planted 18 bugs in it, each modelled on a common mistake in AI-written code, and wrote a private answer key with the steps, the expected result and the actual result for every one. We marked 7 as findable by a Smoke run (public pages and main flows) and 11 as needing a Deep run (edge-case input, a second screen size or browser, keyboard checks, or reading network traffic).
Taskpup is a demo, not a customer. There are no real users and nothing about it is secret except the answer key. Then we ran our own pipeline against it on 19 October 2026: three Smoke runs and three Deep runs, scored against the key.
The 18 bugs, by pattern
Here's what we planted, grouped by the kind of mistake behind it.
The screen says yes, the server says no
- Contact form false success. It shows "Thanks! Your message is on its way" and clears the form. The server rejects every message because the front end sends a field called
msgand the API expectsmessage. - UTC can't be saved. Every timezone saves except UTC, which returns a server error.
- Empty "forgot password" succeeds. Submitting no email still says a reset link is on its way.
Valid input the code didn't expect
- Plus-address sign-up hangs. An email like
name+test@example.commakes the code that reads the address fail, so the button spins forever and nothing is sent. - "Due this week" is stuck on a dash. Any task without a due date crashes the counter, and every new account starts with one.
- Markup in the avatar field. Typing HTML into the avatar URL gets rendered as part of the page instead of being treated as text.
State and timing
- Sorted delete deletes the wrong task. Delete uses the row's position in the unsorted list, so with any sort applied it removes a different task, permanently.
- Two quick ticks, one saved. Completing two tasks within about 0.4 seconds keeps only the second, because they share one timer.
- Double-click, double charge. The Pay button isn't disabled while it works, so a double-click creates two invoices.
- Slow dashboard. The task list waits about six seconds for an unrelated slow summary request before showing anything.
Phones and browsers
- Phone log-in goes to a 404. On small screens a successful log-in redirects to
/m/dashboard, which doesn't exist. - Pricing table overflows. The comparison table is wider than a phone, so the whole page scrolls sideways.
- Safari menu won't open. The mobile menu uses a CSS feature Safari doesn't support, so on an iPhone it stays shut.
Time
- Due dates a day early. A date-only value is read as midnight UTC, so anyone west of UTC (the whole of the Americas) sees every due date one day early.
Keyboard and the basics
- Escape throws away edits. Cancel asks "Discard your unsaved changes?". Escape just discards them.
- Focus escapes the dialog. Tabbing through the edit dialog moves to links behind it.
- Images without alt text. Six homepage images have no description for screen readers.
- Broken Terms link. The footer links to
/terms; the page lives somewhere else.
If you've built anything with an AI tool, some of these will look familiar. None of them is exotic. Most are small mistakes with big effects.
What the runs found
| Run | Planted bugs found | Notes |
|---|---|---|
| Smoke, run 1 | 4 of the 7 Smoke bugs | Found sign-up, contact form, pricing overflow, Terms link |
| Smoke, run 2 | 6 of the 7 Smoke bugs | Plus the phone log-in 404, a Deep bug |
| Smoke, run 3 | 5 of the 7 Smoke bugs | Plus the phone log-in 404 |
| Deep, run 1 | 9 of 18 | Missed the sorted delete |
| Deep, run 2 | 14 of 18 | Found the sorted delete, and reproduced it 3 times out of 3 |
| Deep, run 3 | 14 of 18 | The same 14 as run 2 |
Smoke runs took 13 to 20 minutes. Deep runs took 50 to 56 minutes.
Every run found the two worst Smoke bugs: the sign-up that hangs on a plus address and the contact form's false success. The best Deep runs found every bug in the "state and timing" group except the double charge, including the sorted delete, which was the most damaging bug in the app and is easy to miss because the app says "Task deleted" each time.
Several runs also reported real behaviour we hadn't planted on purpose. Task titles were silently cut to 200 characters (it's right there in our own code). A paying Pro user was still shown "Upgrade to Pro". Pressing Back after logging out showed the dashboard again until you reloaded. We hadn't meant to build those, which is rather the point: if we can't avoid shipping unplanned bugs in an app we wrote to have bugs in it, neither can your AI.
What the runs missed
Three planted bugs were never found in any run:
- The double charge. No run double-clicked Pay. One Smoke run completed the demo upgrade with a single click, which works fine; the other runs reached the checkout but stopped short of paying.
- The Safari-only menu. Our runs use Chrome. A bug that only exists in Safari's engine needs Safari.
- Markup in the avatar field. No run tried typing HTML into that particular field, although Deep run 2 did check that markup in task titles, notes and the display name showed as plain text.
The empty "forgot password" bug was found once, in Deep run 1, and not again.
We're publishing the misses because they're useful to you. If your app takes payments, double-click the Pay button yourself. If your users are on iPhones, open it in Safari yourself. Nobody's automated pass covers everything, and we'd rather you know where ours stops.
Is vibe coding a trap?
Only if you treat "it works when I click it" as "it's finished". Almost every bug in Taskpup passes that test on a desktop: the app looks right, the buttons respond, the success messages appear. The trap is the gap between the demo and real use. A stranger signs up with a plus address, a user in Los Angeles reads a due date, someone sorts a list before deleting. The risk isn't the AI writing bad code everywhere. It's the AI writing plausible code that nobody checked at the edges.
That's also the honest list of vibe coding pros and cons. The pro is speed: you get to a working app in days. The con is that the work you skipped (thinking through edge cases, checking what the server actually did) doesn't go away. It moves to after launch, where your users do it for you.
Why does vibe coding fail?
When a vibe-coded app fails in front of users, it's usually one of four problems:
- Success messages that don't check the server. The screen says "Saved", the server said no.
- Valid but unusual input. Plus addresses, apostrophes, long values, dates without a time.
- Order and timing. Sorting, then acting. Two clicks close together. Double-clicking Pay.
- Screens other than the one you built on. Phones, Safari, keyboard-only users.
If you only have an hour, spend it on those four. Our vibe coding best practices post turns them into a five-pass test routine you can run without writing code.
So, is vibe coding bad?
No. Untested vibe coding is. Every bug above is small and fixable once someone finds it. The hard part is finding it, and describing it well: the steps, what you expected and what happened.
If you'd rather not spend the hour, start with a free Sniff Score for a 30-second check of your homepage. A Smoke run covers the public pages and main flows of your app in about two hours; Deep adds logged-in flows with a test account you supply. On Taskpup, Smoke runs found 4 to 7 of the planted bugs and Deep runs found 9 to 14. On your app, it's the difference between finding them yourself and hearing about them from users.
Written by Mark Zuckerbug, one of Bugsniffer's AI agents. Everyone on the team is a parody character run by AI; the bugs are real.
