debugging-ai-code
Teaches how to debug code generated by AI tools, covering the unique failure modes of AI-generated code including hallucinated APIs, version mismatches, circular logic, and phantom dependencies. Explains how to read error messages back to the AI effectively, provide minimal reproductions, diagnose when the AI is giving bad fixes, and use systematic debugging approaches on codebases you did not write by hand. Use when AI-generated code is not working and you need to find and fix the issue.
Systematic strategies for diagnosing and fixing the unique failure modes of AI-written code. ## Key Points - Next.js 12.3.4 (Pages Router, NOT App Router) - TypeScript 4.9 1. **What you did** — the exact command or action 2. **What happened** — the full error message, copied as text 3. **Where it happened** — file path and line number from the stack trace 4. **What you expected** — what should have happened instead 5. **What you already checked** — prevents the AI from suggesting things you tried - The first line (error type and message) - The first 2-3 frames that reference YOUR code (not `node_modules`) - The file and line number 1. Start with the failing code 2. Remove everything that does not affect the bug ## Quick Example ```python # AI generated this — pandas has no .smart_merge() df = pd.smart_merge(left_df, right_df, on='id', strategy='fuzzy') # What actually works df = pd.merge(left_df, right_df, on='id', how='inner') ``` ``` It's not working. Can you fix it? ```
skilldb get vibe-coding-workflow-skills/debugging-ai-codeFull skill: 371 linesDebugging AI-Generated Code
Systematic strategies for diagnosing and fixing the unique failure modes of AI-written code.
Why AI Code Breaks Differently
AI-generated code fails in ways that human-written code usually does not. Traditional bugs come from logic errors or typos. AI bugs come from the model's training data being outdated, incomplete, or blended across incompatible sources. Understanding these failure categories lets you diagnose faster.
Common AI Failure Modes
1. Hallucinated APIs
The AI invents methods, parameters, or entire libraries that do not exist.
// AI generated this — the method does not exist
const result = await fetch.withRetry('https://api.example.com/data', {
retries: 3,
backoff: 'exponential',
});
// What actually works
const result = await fetch('https://api.example.com/data');
# AI generated this — pandas has no .smart_merge()
df = pd.smart_merge(left_df, right_df, on='id', strategy='fuzzy')
# What actually works
df = pd.merge(left_df, right_df, on='id', how='inner')
How to spot it: The error says X is not a function, module has no attribute X, or no such method. Search the official docs for the exact method name. If it does not appear, the AI invented it.
How to fix it: Tell the AI the exact error and specify the library version you are using. Paste the relevant section of the official docs if the AI keeps hallucinating.
2. Version Mismatches
The AI generates code for a different version of the library than you have installed.
// AI wrote Next.js 14+ App Router code
// But you are on Next.js 12 with Pages Router
export default function Page() {
// 'use client' directive, server components, etc.
}
// Your project actually needs
export default function Page() {
return <div>...</div>;
}
export async function getServerSideProps() {
// ...
}
How to spot it: Code looks syntactically valid but uses patterns you do not recognize from your project. Check package.json or requirements.txt for actual installed versions.
How to fix it: Always tell the AI your exact versions up front:
I am using:
- Next.js 12.3.4 (Pages Router, NOT App Router)
- React 17
- TypeScript 4.9
Do not use features from newer versions.
3. Circular Logic and Infinite Loops
AI generates functions that call each other in circles, or retry logic that never terminates.
# AI-generated "retry with fallback" that loops forever
def get_data(source="primary"):
try:
return fetch_from(source)
except ConnectionError:
if source == "primary":
return get_data("fallback")
else:
return get_data("primary") # Back to primary — infinite loop
How to spot it: The app hangs, CPU spikes, or you hit maximum recursion depth. Trace the call chain manually: does every path eventually terminate?
How to fix it: Add a max_retries counter or tell the AI explicitly: "The fallback must not recurse back to the primary source."
4. Phantom Imports
The AI imports modules that are not installed, or imports from the wrong package.
// AI imports from a package that sounds right but is wrong
import { createClient } from 'redis'; // correct package
import { createClient } from 'redis-client'; // does not exist
// Or imports a subpath that does not exist
import { helper } from 'lodash/utils/helper'; // no such path
How to spot it: Module not found, Cannot find module, No module named X.
How to fix it: Check npm/PyPI for the actual package name. Tell the AI which packages are already in your project.
5. Confidently Wrong Logic
The code runs without errors but produces incorrect results.
# AI-generated discount calculation
def apply_discount(price, discount_percent):
return price - (price * discount_percent)
# If discount_percent=20, this subtracts 20x the price
# AI confused percentage (20) with decimal (0.20)
# Correct
def apply_discount(price, discount_percent):
return price * (1 - discount_percent / 100)
How to spot it: Only by testing with known inputs and expected outputs. This is the hardest failure mode because there is no error message.
How to fix it: Write explicit test cases and share them with the AI. "Given price=100 and discount=20, the result should be 80."
6. Merged Incompatible Patterns
The AI blends patterns from different frameworks, languages, or paradigms into one incoherent file.
// AI mixed Express.js patterns into a Next.js API route
export default function handler(req, res) {
const app = express(); // Wrong — you are already in a handler
app.use(cors());
app.get('/api/data', (req, res) => { // Nested handler — broken
res.json({ data: [] });
});
}
How to spot it: The code has redundant layers, framework boilerplate inside framework boilerplate, or patterns that feel like they belong in a different kind of file.
Reading Error Messages Back to the AI
The biggest skill gap in vibe coding is how you report errors to the AI. Bad error reports produce bad fixes.
Anti-Pattern: Vague Error Report
It's not working. Can you fix it?
The AI has no idea what "not working" means. It will guess, change something random, and possibly break something else.
Anti-Pattern: Screenshot of Terminal
A screenshot loses formatting, is not searchable, and the AI cannot always read it accurately. Copy and paste the text.
Effective Error Reporting Template
I ran this command:
npm run dev
I got this error:
TypeError: Cannot read properties of undefined (reading 'map')
at UserList (src/components/UserList.tsx:14:22)
at renderWithHooks (node_modules/react-dom/...)
The relevant code is in src/components/UserList.tsx lines 10-20.
The `users` prop is coming from a fetch call in src/pages/index.tsx.
I expect `users` to be an array, but it appears to be undefined
on first render before the fetch completes.
The Five Components of a Good Error Report
- What you did — the exact command or action
- What happened — the full error message, copied as text
- Where it happened — file path and line number from the stack trace
- What you expected — what should have happened instead
- What you already checked — prevents the AI from suggesting things you tried
Trimming Stack Traces
You do not need the entire stack trace. Include:
- The first line (error type and message)
- The first 2-3 frames that reference YOUR code (not
node_modules) - The file and line number
# Too much — the AI gets distracted by framework internals
TypeError: Cannot read properties of undefined (reading 'map')
at UserList (src/components/UserList.tsx:14:22)
at renderWithHooks (react-dom.development.js:14985:18)
at mountIndeterminateComponent (react-dom.development.js:17811:13)
at beginWork (react-dom.development.js:19049:16)
... 40 more lines of React internals
# Just right
TypeError: Cannot read properties of undefined (reading 'map')
at UserList (src/components/UserList.tsx:14:22)
Providing Minimal Reproductions
When the AI cannot fix a bug from the error alone, give it a minimal reproduction.
What a Minimal Reproduction Is
The smallest possible code that triggers the exact same bug. Strip away everything unrelated.
// Your full component is 200 lines. The bug is in this part:
function UserList({ users }) {
// BUG: users is undefined on first render
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
// Minimal reproduction:
// 1. users prop can be undefined
// 2. .map() is called without a guard
// 3. Crashes on initial render before data loads
How to Build a Minimal Reproduction
- Start with the failing code
- Remove everything that does not affect the bug
- Replace external dependencies with hardcoded values
- Verify the stripped-down version still fails the same way
- Share the minimal version with the AI
Anti-Pattern: Sending the Entire Codebase
Here is my whole project. Something is broken. Fix it.
The AI will skim, guess, and likely change the wrong thing. Minimal reproductions focus the AI on the actual problem.
Breaking Out of AI Debugging Loops
The AI suggests a fix. It does not work. You tell the AI. It suggests another fix. That breaks something else. You are now in a loop.
The Three-Strike Rule
If the AI has not fixed the bug in three attempts, stop prompting and switch strategies:
- Read the code yourself. Trace the data flow manually. The AI may be misunderstanding the architecture.
- Search the docs. The AI may be wrong about how a library works. Check the source.
- Isolate the layer. Is the bug in the frontend, the API, the database, or the config? Test each layer independently.
- Start a new conversation. Stale context from failed attempts pollutes the AI's reasoning. Start fresh with just the error and the relevant code.
When to Add Context vs. Start Over
Add context if the AI is close but missing one piece of information (a type definition, a config value, a version number).
Start over if the AI is going in circles, suggesting the same fix with minor variations, or if the conversation is longer than 20 messages about the same bug.
Manual Debugging Checklist
Before asking the AI again, verify these yourself:
[ ] Is the error message from the current code? (not cached/stale)
[ ] Are all dependencies installed? (npm install / pip install)
[ ] Is the dev server restarted? (some changes need a restart)
[ ] Are environment variables set? (.env file present and loaded)
[ ] Is the correct version of the runtime? (node -v, python --version)
[ ] Is the database running and accessible?
[ ] Are there TypeScript or build errors the AI did not address?
Debugging Strategies by Error Type
Runtime Errors (crashes)
- Copy the error and stack trace
- Identify the file and line in YOUR code (ignore framework internals)
- Check what variable is undefined/null and trace where it should come from
Build Errors (compilation failures)
- These are usually the easiest: the error tells you exactly what is wrong
- Common AI causes: wrong TypeScript types, missing imports, syntax from a different language
- Give the AI the exact error — build errors are unambiguous
Silent Failures (no error, wrong behavior)
- Add logging at each step to find where actual behavior diverges from expected
- Write a test with expected input/output and share the failing test with the AI
- These are the hardest bugs; do not expect the AI to fix them without specific evidence
Configuration Errors (things that should work but do not)
- AI frequently generates wrong config (webpack, tsconfig, Docker, CI/CD)
- Compare AI-generated config against the official docs or a known-working config
- Do not ask the AI to guess at config — paste the docs and ask it to match
Systematic AI Code Review
When the code appears to work but you want to catch hidden bugs before they surface:
Check These AI Blind Spots
// 1. Error handling — AI often catches and swallows
try { riskyOperation(); } catch (e) { console.log(e); }
// Fix: rethrow, return error, or handle meaningfully
// 2. Edge cases — AI tests the happy path
function divide(a: number, b: number) { return a / b; }
// Missing: what if b is 0? What if inputs are NaN?
// 3. Security — AI skips input sanitization
const query = `SELECT * FROM users WHERE id = ${userId}`;
// Fix: use parameterized queries
// 4. Async race conditions — AI assumes sequential execution
const [users, posts] = [await getUsers(), await getPosts()];
// This is sequential. Did the AI mean Promise.all?
// 5. Memory leaks — AI forgets cleanup
useEffect(() => {
const interval = setInterval(fetchData, 5000);
// Missing: return () => clearInterval(interval);
}, []);
Anti-Patterns Summary
| Anti-Pattern | Why It Hurts | Fix |
|---|---|---|
| "It's not working, fix it" | AI guesses randomly | Provide error, context, expectation |
| Pasting full stack traces | AI focuses on irrelevant frames | Trim to your code only |
| Debugging loop past 3 tries | Diminishing returns, compounding changes | Stop, diagnose manually, fresh session |
| Not checking versions | AI writes code for wrong library version | State versions explicitly |
| Trusting code that runs without errors | Silent logic bugs are the most dangerous | Test with known inputs and outputs |
| Sending entire codebase for one bug | AI loses focus | Provide minimal reproduction |
| Not restarting after config changes | Stale cache masks the fix | Restart dev server, clear caches |
Install this skill directly: skilldb add vibe-coding-workflow-skills
Related Skills
ai-pair-programming
Teaches effective AI pair programming techniques for tools like Claude Code, Cursor, and Copilot. Covers when to lead versus follow the AI, providing persistent context through CLAUDE.md and .cursorrules files, breaking complex tasks into AI-manageable pieces, using git strategically with frequent commits as checkpoints, and recognizing when the AI is stuck in a loop. Use when working alongside AI coding tools in a collaborative development workflow.
maintaining-ai-codebases
Covers the unique challenges of maintaining codebases built primarily through AI code generation. Addresses inconsistent patterns across AI-generated files, refactoring AI sprawl, establishing coding conventions after the code already exists, documentation strategies for AI-built projects, and managing the specific forms of technical debt that AI tools create. Use when a vibe-coded project needs ongoing maintenance or has grown unwieldy.
prompt-to-app
Guides the complete journey from an idea to a working application using AI code generation tools. Covers writing effective app specifications, choosing the right tool for the job (Claude Code, Cursor, Bolt, v0, Lovable, Replit Agent), the spec-first approach, iterating on generated code without losing coherence, and managing scope creep during AI-assisted development. Use when someone wants to build an app from scratch using vibe coding.
reviewing-ai-code
Teaches how to review, audit, and evaluate AI-generated code effectively. Covers common AI code smells like over-engineering, dead code, wrong abstractions, and hallucinated APIs. Includes security review checklists, dependency auditing, performance review techniques, and strategies for catching the subtle bugs that AI confidently introduces. Use when reviewing code produced by any AI coding tool.
scaling-past-vibe
Guides the transition from a vibe-coded prototype to a production-grade application. Covers identifying when the project has outgrown pure vibe coding, refactoring AI-generated code for production reliability, adding tests retroactively to an untested codebase, introducing CI/CD pipelines, establishing code ownership and review processes, and building the engineering practices needed to sustain a growing application. Use when a vibe-coded project is succeeding and needs to become a real product.
vibe-coding-architecture
Covers architecture decisions optimized for AI-assisted development. Teaches how to choose frameworks and structures that AI tools work well with, why monolith-first is the right default for vibe coding, how to organize files so AI can navigate them, which abstraction patterns help versus hinder AI code generation, and how to keep complexity within the bounds of what AI can reason about. Use when making technology and architecture choices for a vibe-coded project.