The demo worked. Obviously it worked.
You built the thing in a weekend with Cursor, Claude, Replit, Lovable - whatever tool you're using this week (Edit as of March of 2026: my new fav is v0 by Vercel) You shipped. You got a few users. Somebody may have even paid you. Then Monday hits with a bug report that starts with: "Hey, your app crashes and I can't log in anymore."
That's the vibe coding hangover. And yes, I get it. I vibe code a lot now too. AI made me faster. The problem is fast doesn't mean good. In the good old days it would take months to build a pile of garbage. Now, you can ship a mess in a weekend! Progress.
The common failure modes (aka: why your users found the edge cases)
Here's what shows up most often after the first ship:
-
No tests, not even a sad little smoke test.
The app "works" until a dependency updates or a user types a character you didn't imagine. -
Error handling is vibes-based.
Lots oftry/except: passeverywhere. Or worse, exceptions leak into the UI and users become your QA team. -
Hardcoded secrets.
Keys in the repo. Keys in the frontend. Keys in the logs. Keys in screenshots in your support channel. It turns into a scavenger hunt, except the prize is someone somehow charging ads to... your Stripe account? -
Missing input validation.
"It's a text box, what could go wrong?" A lot. CSV injection. Prompt injection. Path traversal. Or just a user pasting a 20MB blob and taking down your tiny server. True story. -
Architecture that makes sense to the AI but not to humans.
Ten files namedutils.py. Business logic in the request handler. Database calls scattered across the codebase. It runs, but nobody can reason about it.
Vibe coding can also trick you. You can ship something impressive and still not be able to maintain it.
A triage framework that won't ruin your week
You don't fix everything at once. You fix the stuff that can end the business first.
- Stop the bleeding (security + money).
- Rotate all keys. Assume they leaked.
- Move secrets to env vars or better a secret manager.
- Add rate limiting and basic auth rules.
-
Lock down file uploads and any "run arbitrary text through a tool" features.
-
Make failures visible (observability).
- Add structured logging.
- Capture exceptions with something like Sentry.
-
Add request IDs so you can trace a single user's bad day.
-
Stabilize core flows (tests where it matters).
Pick 3โ5 critical paths (signup, login, payment, primary action). Write boring tests.
python def test_checkout_rejects_negative_quantity(client): res = client.post("/checkout", json={"sku": "abc", "qty": -1}) assert res.status_code == 400
You're not chasing 100% coverage. You're building tripwires. -
Document the parts you'll forget.
- "How to run locally"
- "How to deploy"
- "Where the data lives"
- "What jobs run in the background"
Future-you is a stranger. Write for them.
- Decide: patch or rewrite.
Patch if: - the data model is sane
- the boundaries are mostly clear
- you can add tests without crying
Rewrite if:
- every change breaks two unrelated things
- you can't explain the flow from request - logic - DB - response
- the AI generated a maze of abstractions that nobody asked for
The quiet truth
Shipping an MVP is easy now. Keeping it alive is still work.
I consult because I like working on problems I can actually fix. Companies die for all sorts of reasons-no traction, bad timing, bad pricing, internal politics. Engineers still end up holding the bag for half of that. I stay focused on the software: make it readable, make it testable, make it behave.
Vibe code your MVP. Seriously. Just don't confuse "demo-ready" with "production-ready." If you triage early, you can keep the speed without signing up for the pain.
-Sethers