Debugging AI-Generated Code
Reviewing AI-Generated Code
4 min read
AI-generated code requires careful review before deployment. This lesson teaches systematic review techniques to catch issues early.
The Review Mindset
Trust but verify:
├── AI makes mistakes
├── Context can be misunderstood
├── Edge cases are often missed
├── Security requires human judgment
└── Performance implications need review
Never ship unreviewed AI code to production.
The Review Checklist
1. Logic Verification
□ Does it solve the actual problem?
□ Is the algorithm correct?
□ Are edge cases handled?
□ Is the control flow logical?
□ Do loops terminate properly?
Example: Checking Logic
AI generates:
function findMax(numbers: number[]): number {
return Math.max(...numbers);
}
Review questions:
- What if array is empty? (Returns -Infinity, might want null or throw)
- What about very large arrays? (Stack overflow with spread)
- Is null/undefined handled?
2. Type Safety
□ Are types properly defined?
□ Any use of 'any'?
□ Are generics used appropriately?
□ Null/undefined handling?
□ Type narrowing in conditionals?
Example: Spotting Type Issues
AI generates:
function getUserData(id: string): User {
const data = localStorage.getItem(`user_${id}`);
return JSON.parse(data); // ⚠️ Problem!
}
Issues:
getItemcan returnnullJSON.parse(null)throws- No type validation on parsed data
Fixed:
function getUserData(id: string): User | null {
const data = localStorage.getItem(`user_${id}`);
if (!data) return null;
try {
return JSON.parse(data) as User; // Consider runtime validation
} catch {
return null;
}
}
3. Error Handling
□ Are errors caught appropriately?
□ Are error messages helpful?
□ Does error handling prevent crashes?
□ Are errors logged?
□ Are errors propagated correctly?
Example: Missing Error Handling
AI generates:
async function fetchUser(id: string) {
const response = await fetch(`/api/users/${id}`);
return response.json(); // ⚠️ Problems!
}
Issues:
- No check for response.ok
- No try/catch for network errors
- No handling for non-JSON responses
4. Security Scan
□ Input validation present?
□ No SQL/NoSQL injection?
□ No XSS vulnerabilities?
□ Proper authentication checks?
□ No exposed secrets?
□ Safe data handling?
Example: Security Issue
AI generates:
app.get('/user/:id', (req, res) => {
const query = `SELECT * FROM users WHERE id = ${req.params.id}`;
db.execute(query); // ⚠️ SQL Injection!
});
Fixed:
app.get('/user/:id', (req, res) => {
const query = 'SELECT * FROM users WHERE id = ?';
db.execute(query, [req.params.id]);
});
5. Performance Check
□ No unnecessary loops?
□ Database queries optimized?
□ Memory usage reasonable?
□ No blocking operations?
□ Caching considered?
Example: Performance Issue
AI generates:
async function getAllUserPosts(userIds: string[]) {
const posts = [];
for (const id of userIds) {
const userPosts = await db.posts.findMany({ where: { userId: id } });
posts.push(...userPosts);
}
return posts;
}
Issue: N+1 query problem
Fixed:
async function getAllUserPosts(userIds: string[]) {
return db.posts.findMany({
where: { userId: { in: userIds } }
});
}
Common AI Code Patterns to Watch
Pattern 1: Over-Engineering
AI sometimes generates overly complex solutions:
// AI generated
class UserValidator {
private static instance: UserValidator;
private validationRules: Map<string, Rule[]>;
private constructor() {
this.validationRules = new Map();
this.initializeRules();
}
static getInstance() {
if (!this.instance) {
this.instance = new UserValidator();
}
return this.instance;
}
// ... 100 more lines
}
// What was needed
function validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
Pattern 2: Missing Null Checks
// AI generated
function getUsername(user: User): string {
return user.profile.displayName.toUpperCase();
}
// What's needed
function getUsername(user: User): string {
return user?.profile?.displayName?.toUpperCase() ?? 'Anonymous';
}
Pattern 3: Incorrect Async Handling
// AI generated
async function processItems(items: Item[]) {
items.forEach(async (item) => { // ⚠️ Won't await!
await processItem(item);
});
}
// Fixed
async function processItems(items: Item[]) {
await Promise.all(items.map(item => processItem(item)));
}
Pattern 4: Incomplete Error Boundaries
// AI generated
try {
const data = await fetch('/api/data');
} catch (error) {
console.log('Error'); // ⚠️ Swallowed error, no context
}
// Fixed
try {
const data = await fetch('/api/data');
} catch (error) {
console.error('Failed to fetch data:', error);
throw new ApiError('DATA_FETCH_FAILED', error);
}
Review Workflow
Step 1: Quick Scan
- Read through once for overall understanding
- Note anything that feels "off"
Step 2: Deep Analysis
- Check each function's logic
- Trace data flow
- Verify error handling
Step 3: Security Audit
- Look for injection points
- Check authentication/authorization
- Review data exposure
Step 4: Test Mentally
- Imagine edge case inputs
- Consider failure scenarios
- Think about performance at scale
Step 5: Request Changes
Ask AI to fix:
"In the generated code, I noticed:
1. Missing null check on line 23
2. SQL injection vulnerability on line 45
3. N+1 query issue in getUserPosts
Please fix these issues."
Tools for Review
TypeScript Strict Mode
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}
ESLint Security Rules
// .eslintrc
{
"plugins": ["security"],
"extends": ["plugin:security/recommended"]
}
Manual Testing
For each function:
├── Test with valid input
├── Test with empty input
├── Test with null/undefined
├── Test with invalid types
└── Test with edge cases
Review Principle: The 30 seconds you spend reviewing can save hours of debugging in production. Make review a habit, not an afterthought.
In the next lesson, we'll cover common bugs in AI-generated code and how to fix them. :::