Debug common issues with authentication, payments, database queries, React components, and API routes. Use when troubleshooting errors, investigating bugs, or diagnosing unexpected behavior.
Solutions for common issues in this application.
| Symptom | Likely Cause | Check |
|---|---|---|
| 401 Unauthorized | Session expired/missing | Cookie presence, session expiry |
| 403 Forbidden | Wrong role | User role in database |
| 429 Too Many Requests | Rate limited | Wait for retry-after |
| 500 Server Error | Unhandled exception | Server logs |
| Empty response | Query returned nothing | Database data |
| Stale data | Cache not invalidated | React Query cache |
| Form not submitting | Validation error | Console, field errors |
Check session cookie:
// In browser DevTools > Application > Cookies
// Look for 'session' cookie
// Or in API route:
const cookie = request.headers.get('cookie')
console.log('Cookie header:', cookie)
Check session in database:
SELECT * FROM sessions WHERE id = 'session-id-from-cookie';
-- Check expires_at is in the future
Common fixes:
credentials: 'include' in fetch callsCheck user role:
SELECT id, email, role FROM users WHERE id = 'user-id';
-- Should be 'admin' for admin routes
Fix:
UPDATE users SET role = 'admin' WHERE email = '[email protected]';
Check password hash:
import { verify } from 'bcrypt-ts'
const isValid = await verify(inputPassword, user.passwordHash)
console.log('Password valid:', isValid)
Common issues:
Check data exists:
SELECT * FROM products WHERE id = 'product-id';
SELECT * FROM products WHERE handle = 'product-handle';
Check query conditions:
// Add logging
console.log('Query params:', { search, status, page })
const results = await db.select().from(products).where(whereClause)
console.log('Results:', results.length)
Symptom: Slow API responses, many database queries
Diagnose:
// Add query logging in db/index.ts
const db = drizzle(pool, {
logger: true, // Logs all queries
})
Fix: Use batch queries with Maps (see database skill)
Check migration status:
yarn db:studio # Open Drizzle Studio
Reset and retry:
# Development only!
yarn db:push # Push schema directly
Check for conflicts:
-- Check existing tables/columns
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'your_table';
Check Content-Type:
console.log('Content-Type:', request.headers.get('content-type'))
// Must be application/json for JSON body
const body = await request.json()
console.log('Body:', body)
Fix frontend:
fetch('/api/resource', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
credentials: 'include',
})
Symptom: "CORS policy" error in browser console
Check:
Symptom: 429 Too Many Requests
Check Retry-After header:
const response = await fetch('/api/auth/login', { ... })
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After')
console.log('Wait seconds:', retryAfter)
}
Tiers:
auth: 5 requests per 15 minutesapi: 100 requests per minutewebhook: 50 requests per minuteCheck PaymentIntent status:
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId)
console.log('Status:', paymentIntent.status)
console.log('Last error:', paymentIntent.last_payment_error)
Common issues:
Check webhook configuration:
Test locally with Stripe CLI:
stripe listen --forward-to localhost:3000/api/webhooks/stripe
Check signature:
try {
const event = stripe.webhooks.constructEvent(body, sig, secret)
} catch (err) {
console.error('Webhook signature failed:', err.message)
}
Check expiration:
SELECT id, expires_at, completed_at
FROM checkouts
WHERE id = 'checkout-id';
Extend expiration (dev only):
UPDATE checkouts
SET expires_at = NOW() + INTERVAL '24 hours'
WHERE id = 'checkout-id';
Check React Query cache:
// Force refetch
const queryClient = useQueryClient()
queryClient.invalidateQueries({ queryKey: ['products'] })
Check Zustand state:
// In browser DevTools console
const state = useCartStore.getState()
console.log('Cart items:', state.items)
Check field configuration:
{
name: 'email',
type: 'email',
label: 'Email',
required: true, // Must be true for validation
validate: (value) => {
console.log('Validating:', value) // Debug
if (!value) return 'Required'
},
}
Check form ref:
const formRef = useRef<FNFormRef | null>(null)
// Is ref connected?
console.log('Form ref:', formRef.current)
// Try manual submit
formRef.current?.submit()
Symptom: "Text content does not match" warning
Common causes:
Fix:
// Use useEffect for client-only values
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return <Skeleton />
return <ClientOnlyComponent />
Symptom: Shows key instead of translation
Check:
Debug:
const { t, i18n } = useTranslation()
console.log('Current lang:', i18n.language)
console.log('Translation:', t('key', { returnDetails: true }))
// In API route
import { logRequest, createRequestTimer } from '@/lib/logger'
GET: async ({ request }) => {
const timer = createRequestTimer()
try {
// ... handler logic
logRequest(request, response, timer)
return response
} catch (error) {
logError('Handler failed', error, { url: request.url })
throw error
}
}
// Temporarily enable query logging
import { drizzle } from 'drizzle-orm/node-postgres'
const db = drizzle(pool, {
logger: {
logQuery(query, params) {
console.log('Query:', query)
console.log('Params:', params)
},
},
})
| Error | Meaning | Fix |
|---|---|---|
ECONNREFUSED | Database not running | Start PostgreSQL |
relation does not exist | Table missing | Run migrations |
duplicate key value | Unique constraint | Check for existing record |
invalid input syntax for type uuid | Bad UUID format | Validate UUID before query |
JWT expired | Token expired | Refresh token or re-auth |
rate limit exceeded | Too many requests | Wait and retry |
// Check at startup
const required = ['DATABASE_URL', 'STRIPE_SECRET_KEY', 'CHECKOUT_SECRET']
for (const key of required) {
if (!process.env[key]) {
throw new Error(`Missing required env var: ${key}`)
}
}
// Check which environment
console.log('NODE_ENV:', process.env.NODE_ENV)
console.log('Is production:', process.env.NODE_ENV === 'production')
# Check database connection
yarn db:studio
# Run single test with logging
yarn vitest run path/to/test.ts --reporter=verbose
# Type check
yarn typecheck
# Check for lint errors
yarn lint
# View build output
yarn build && ls -la .output/
api-routes skill - API debugging patternsdatabase skill - Query debuggingcheckout skill - Payment debuggingtesting skill - Test debuggingsecurity skill - Auth debugging