Debugging a Broken Vibe-Coded App: Symptom-by-Symptom Runtime Triage
How to diagnose and fix five common runtime breakdowns in Bolt, Lovable, v0, and Cursor codebases.

When an AI-generated app breaks during user testing or runtime deployment, the breakdown is rarely a random syntax error. It stems from five predictable structural fractures: client-side hydration mismatches, serverless connection pool exhaustion, unhandled LLM streaming timeouts, hallucinated module imports, and silent session invalidation. Prompting an AI model to fix these symptoms blindly usually creates circular regressions.
Fixing a broken vibe-coded app requires isolating the runtime boundary, identifying the exact failure mechanism, and applying deterministic engineering remedies before writing more prompts.
The short version
Do not ask the AI assistant to "fix the bug" without inspecting the browser console and server logs. Triage the failure symptom first:
- Hydration errors require moving client-only globals (
window,localStorage) into controlled lifecycle hooks. - Database exhaustion requires pooling singletons across serverless invocations.
- LLM timeouts require explicit abort controllers and max-token bounds.
- Hallucinated imports require replacing phantom packages with verified libraries.
- Dropped sessions require aligning middleware cookie domains with the backend auth provider.
Use our AI-generated code audit checklist to audit the rest of your app once these runtime fires are contained.
Symptom 1: React Hydration Mismatch and Infinite Render Loops
The error in the console:
Error: Text content does not match server-rendered HTML. or Too many re-renders. React limits the number of renders to prevent an infinite loop.
Why AI generators cause this:
LLMs often access browser globals directly inside React component bodies (such as window.innerWidth, localStorage.getItem("token"), or new Date().toLocaleTimeString()). During Server-Side Rendering (SSR) in Next.js or Remix, the server generates HTML without access to browser state. When the client loads and renders a different value, React fails hydration and either re-renders the whole tree or gets trapped in an infinite useEffect cycle.
How to diagnose: Open browser DevTools and look for hydration warnings. Inspect the component tree to identify which element has differing server and client attributes.
The fix: Defer access to browser globals until after the component mounts on the client:
// Broken AI pattern: evaluating window during initial render
export function UserStatus() {
const isOnline = window.navigator.onLine; // Breaks SSR hydration
return <div>{isOnline ? "Online" : "Offline"}</div>;
}
// Deterministic fix: defer to client mount
export function UserStatus() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
setIsOnline(window.navigator.onLine);
const handleStatus = () => setIsOnline(window.navigator.onLine);
window.addEventListener("online", handleStatus);
window.addEventListener("offline", handleStatus);
return () => {
window.removeEventListener("online", handleStatus);
window.removeEventListener("offline", handleStatus);
};
}, []);
return <div>{isOnline ? "Online" : "Offline"}</div>;
}
Symptom 2: Database Connection Pool Exhaustion under Load
The error in the logs:
FATAL: remaining connection slots are reserved for non-replication superuser connections or Prisma error P2024: Timed out fetching a new connection from the connection pool.
Why AI generators cause this: AI prompts generate Prisma or PostgreSQL clients directly inside individual API route handlers or server actions:
// Broken AI pattern: instantiating client per request
import { PrismaClient } from "@prisma/client";
export async function GET() {
const prisma = new PrismaClient(); // Creates a new pool per function execution!
const users = await prisma.user.findMany();
return Response.json(users);
}
In a serverless environment (such as Vercel or AWS Lambda), each incoming request spawns a new runtime container. When 50 concurrent users visit your app, 50 distinct instances each allocate default connection pools, exhausting PostgreSQL's maximum connection limit within seconds.
How to diagnose: Check your database metrics in Supabase, Neon, or AWS RDS. If active connections spike to the limit during modest traffic spikes, your application is instantiating unmanaged clients.
The fix:
- Use a global singleton pattern to preserve database clients across serverless hot reloads:
// lib/db.ts
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const db =
globalForPrisma.prisma ||
new PrismaClient({
log: process.env.NODE_ENV === "development" ? ["query", "error"] : ["error"],
});
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = db;
- Connect through a transaction connection pooler (such as PgBouncer or Supabase Pooler on port 6543) rather than the direct database port.
Symptom 3: 504 Gateway Timeouts and LLM Token Runaway Loops
The error in the logs:
HTTP 504 Gateway Timeout or runaway billing alerts from OpenAI/Anthropic accounts within hours of user testing.
Why AI generators cause this: When building conversational features or autonomous agent loops, vibe-coded apps frequently lack three critical constraints:
- No request timeout or
AbortSignalon fetch calls. - No
max_tokensceiling on LLM completions. - Recursive agent loops that call tools repeatedly when an unexpected output format occurs.
If the LLM generates a rambling output or encounters upstream latency, the host serverless platform terminates the connection after 10–15 seconds with a 504 error, leaving client UI spinners hanging permanently.
How to diagnose:
Review network tabs for API calls to /api/chat or /api/agent. Note requests terminating precisely at your platform's serverless timeout threshold.
The fix:
Wrap downstream model calls with an explicit AbortController and bounded loop limits:
export async function POST(req: Request) {
const { prompt } = await req.json();
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 9000); // 9-second hard deadline
try {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [{ role: "user", content: prompt }],
max_tokens: 600, // Explicit budget ceiling
}),
signal: controller.signal,
});
const data = await response.json();
return Response.json(data);
} catch (error: any) {
if (error.name === "AbortError") {
return new Response("Upstream AI request timed out", { status: 504 });
}
throw error;
} finally {
clearTimeout(timeoutId);
}
}
Symptom 4: Phantom Dependencies and Sandbox Build Failures
The error during build:
Module not found: Can't resolve 'some-react-lucide-icons' or 'shadcn-extended-calendar'.
Why AI generators cause this: In-browser scaffolding platforms (like Bolt or WebContainer-based environments) occasionally mock missing packages or allow loose module resolution that succeeds locally. Furthermore, LLMs hallucinate utility package names that do not exist on the public npm registry. When moving code from a web sandbox into a real repository for production CI/CD, the build immediately crashes.
How to diagnose: Run a clean install and build locally:
rm -rf node_modules .next dist
pnpm install --frozen-lockfile
pnpm run build
The fix: Audit the failing import:
- Search npmjs.com to confirm whether the package actually exists.
- If the package was hallucinated, replace it with the standard ecosystem equivalent (for example, replace hallucinated icon packages with
lucide-react, or replace mock UI components with standard primitives from Radix UI). - Always commit a clean
pnpm-lock.yamlorpackage-lock.jsonand enforce--frozen-lockfilein deployment pipelines.
Symptom 5: Silent Session Invalidation and Edge Cookie Desynchronization
The error experienced by users: Users sign in, but navigating to any protected route immediately logs them out, or state reverts to anonymous after page refresh.
Why AI generators cause this:
AI assistants frequently mix client-side authentication SDKs with server-side edge middleware without configuring cookie domain scopes, SameSite flags, or secure token synchronization. If a client writes an authentication token to localStorage, the Next.js middleware.ts running at the edge cannot read it from incoming HTTP request headers, causing the edge router to redirect users back to /login.
How to diagnose:
Open DevTools Application tab -> Cookies. Observe whether the session cookie (sb-access-token, __session, or auth-token) is present on every subpath and whether the HttpOnly and Secure flags are set.
The fix: Unify authentication around secure HTTP cookies:
- Remove
localStoragetoken storage. - Use your auth provider's official server-side cookie handlers (such as
@supabase/ssror@clerk/nextjs). - Ensure middleware reads the cookie and exchanges refreshed tokens directly in response headers:
// middleware.ts
import { NextResponse, type NextRequest } from "next/server";
import { updateSession } from "@/lib/auth/server";
export async function middleware(request: NextRequest) {
return await updateSession(request);
}
export const config = {
matcher: ["/dashboard/:path*", "/api/protected/:path*"],
};
When to stop patching and seek structured rescue
If fixing one runtime error triggers two regressions elsewhere, your app is suffering from architecture entanglement. Review our guide on how to clean up a vibe-coded app before launch to systematically inspect your code, check 12 critical security flaws in vibe-coded apps to identify hidden vulnerabilities, or examine our guide on Lovable apps moving to production for connection pooling and webhook fixes. You can also review common authorization pitfalls in Bolt, v0, and Replit auth and RLS mistakes.
If the prototype has validated market demand but the codebase has become unmanageable, explore the rescue-vs-rewrite framework, review our sample AI code rescue audit report, or consult our buyer's guide to vibe coding cleanup services to understand deliverable expectations and audit windows.
For teams that need experienced engineers to untangle runtime breakdowns, Aatvi's AI Code Rescue sprint stabilizes database pooling, refactors authentication, and implements defensive CI verification to make AI-built software reliable for production users.
Source notes
- Software architecture triage principles from the Carnegie Mellon University Software Engineering Institute highlight isolating failure blast radiuses and establishing observable telemetry.
- The AWS Architecture Center outlines cloud resilience patterns, including connection pooling, graceful timeout degradation, and circuit breakers.
- IETF standards define foundational HTTP status codes, connection pooling semantics, and cookie handling specifications.
Start here: AI Code Rescue audit and stabilization.
