Troubleshooting
Diagnose and resolve common deployment issues and production problems.
Troubleshooting
Common Deployment Issues
Build Failures
Diagnose and fix build-time problems.
Missing Dependencies
# Error: Module not found
npm list --depth=0 # Check installed packages
npm install --save missing-package
# Clear cache and reinstall
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
Environment Variable Issues
// lib/env-validation.ts
import { z } from 'zod'
const envSchema = z.object({
DATABASE_URL: z.string().url(),
NEXTAUTH_SECRET: z.string().min(32),
NEXTAUTH_URL: z.string().url(),
})
export function validateEnvironment() {
try {
const env = envSchema.parse(process.env)
console.log('✅ Environment variables validated')
return env
} catch (error) {
console.error('❌ Environment validation failed:')
if (error instanceof z.ZodError) {
error.errors.forEach(err => {
console.error(` ${err.path.join('.')}: ${err.message}`)
})
}
process.exit(1)
}
}
Memory Issues During Build
// next.config.mjs - Increase memory for build
/** @type {import('next').NextConfig} */
const nextConfig = {
// Increase memory limit for build
experimental: {
craCompat: true,
esmExternals: false,
},
// Optimize bundle size
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
path: false,
os: false,
}
}
// Split chunks to reduce memory usage
config.optimization.splitChunks = {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
}
return config
},
}
export default nextConfig
Runtime Issues
Application Crashes
Debug and resolve application crashes.
Memory Leaks
// lib/memory-monitor.ts
export class MemoryMonitor {
private intervalId: NodeJS.Timeout | null = null
start(): void {
this.intervalId = setInterval(() => {
const usage = process.memoryUsage()
const heapUsedMB = Math.round(usage.heapUsed / 1024 / 1024)
const heapTotalMB = Math.round(usage.heapTotal / 1024 / 1024)
console.log(`Memory usage: ${heapUsedMB}MB / ${heapTotalMB}MB`)
// Alert if memory usage is too high
if (heapUsedMB > 500) {
console.warn('⚠️ High memory usage detected:', heapUsedMB, 'MB')
// Force garbage collection if available
if (global.gc) {
global.gc()
console.log('🧹 Garbage collection triggered')
}
}
}, 30000) // Check every 30 seconds
}
stop(): void {
if (this.intervalId) {
clearInterval(this.intervalId)
this.intervalId = null
}
}
}
// Start monitoring in production
if (process.env.NODE_ENV === 'production') {
const monitor = new MemoryMonitor()
monitor.start()
// Cleanup on exit
process.on('SIGTERM', () => monitor.stop())
process.on('SIGINT', () => monitor.stop())
}
Unhandled Exceptions
// lib/error-handler.ts
export function setupGlobalErrorHandling(): void {
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error)
// Log to external service
logErrorToService(error, 'uncaughtException')
// Graceful shutdown
process.exit(1)
})
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason)
// Log to external service
logErrorToService(new Error(String(reason)), 'unhandledRejection')
})
}
async function logErrorToService(error: Error, type: string): Promise<void> {
try {
await fetch('/api/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: error.message,
stack: error.stack,
type,
timestamp: new Date().toISOString(),
}),
})
} catch (logError) {
console.error('Failed to log error to service:', logError)
}
}
Database Connection Issues
Resolve database connectivity problems.
Connection Pool Exhaustion
// lib/db-diagnostics.ts
import { Pool } from 'pg'
export class DatabaseDiagnostics {
constructor(private pool: Pool) {}
async getConnectionStats(): Promise<any> {
return {
totalConnections: this.pool.totalCount,
idleConnections: this.pool.idleCount,
waitingClients: this.pool.waitingCount,
}
}
async testConnection(): Promise<boolean> {
try {
const client = await this.pool.connect()
await client.query('SELECT 1')
client.release()
return true
} catch (error) {
console.error('Database connection test failed:', error)
return false
}
}
async getLongRunningQueries(): Promise<any[]> {
const query = `
SELECT
pid,
query,
state,
query_start,
NOW() - query_start AS duration
FROM pg_stat_activity
WHERE state = 'active'
AND NOW() - query_start > INTERVAL '5 minutes'
ORDER BY duration DESC
`
try {
const result = await this.pool.query(query)
return result.rows
} catch (error) {
console.error('Failed to get long running queries:', error)
return []
}
}
}
Connection Timeouts
// lib/db-retry.ts
export async function withRetry<T>(
operation: () => Promise<T>,
maxRetries = 3,
delay = 1000
): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation()
} catch (error) {
if (attempt === maxRetries) {
throw error
}
console.warn(`Attempt ${attempt} failed, retrying in ${delay}ms...`)
await new Promise(resolve => setTimeout(resolve, delay))
delay *= 2 // Exponential backoff
}
}
throw new Error('Max retries exceeded')
}
// Usage example
const result = await withRetry(async () => {
return await db.query('SELECT * FROM users WHERE id = $1', [userId])
}, 3, 1000)
Performance Issues
Slow Response Times
Identify and resolve performance bottlenecks.
API Response Analysis
// lib/performance-monitor.ts
export class PerformanceMonitor {
private metrics = new Map<string, number[]>()
measureApiCall(endpoint: string) {
return (target: any, propertyName: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value
descriptor.value = async function(...args: any[]) {
const startTime = Date.now()
try {
const result = await originalMethod.apply(this, args)
const duration = Date.now() - startTime
this.recordMetric(endpoint, duration)
if (duration > 2000) {
console.warn(`⚠️ Slow API call: ${endpoint} took ${duration}ms`)
}
return result
} catch (error) {
const duration = Date.now() - startTime
console.error(`❌ API call failed: ${endpoint} (${duration}ms)`, error)
throw error
}
}
}
}
private recordMetric(endpoint: string, duration: number): void {
if (!this.metrics.has(endpoint)) {
this.metrics.set(endpoint, [])
}
const measurements = this.metrics.get(endpoint)!
measurements.push(duration)
// Keep only last 100 measurements
if (measurements.length > 100) {
measurements.shift()
}
}
getAverageResponseTime(endpoint: string): number {
const measurements = this.metrics.get(endpoint) || []
if (measurements.length === 0) return 0
const sum = measurements.reduce((a, b) => a + b, 0)
return sum / measurements.length
}
getPercentile(endpoint: string, percentile: number): number {
const measurements = this.metrics.get(endpoint) || []
if (measurements.length === 0) return 0
const sorted = [...measurements].sort((a, b) => a - b)
const index = Math.ceil((percentile / 100) * sorted.length) - 1
return sorted[index]
}
}
Database Query Optimization
-- Find slow queries
SELECT
query,
calls,
total_time,
mean_time,
rows
FROM pg_stat_statements
WHERE mean_time > 1000 -- Queries taking more than 1 second
ORDER BY mean_time DESC
LIMIT 10;
-- Check for missing indexes
SELECT
schemaname,
tablename,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch
FROM pg_stat_user_tables
WHERE seq_scan > idx_scan
AND seq_tup_read > 10000
ORDER BY seq_tup_read DESC;
-- Find unused indexes
SELECT
schemaname,
tablename,
indexname,
idx_scan,
idx_tup_read,
idx_tup_fetch
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;
Diagnostic Tools
Health Check Endpoint
Implement comprehensive health monitoring.
// pages/api/health.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { DatabaseDiagnostics } from '../../lib/db-diagnostics'
interface HealthStatus {
status: 'healthy' | 'unhealthy' | 'degraded'
timestamp: string
checks: {
database: boolean
memory: boolean
disk: boolean
}
metrics: {
uptime: number
memoryUsage: NodeJS.MemoryUsage
responseTime: number
}
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<HealthStatus>
) {
const startTime = Date.now()
try {
// Database check
const dbDiagnostics = new DatabaseDiagnostics(db)
const dbHealthy = await dbDiagnostics.testConnection()
// Memory check
const memoryUsage = process.memoryUsage()
const memoryHealthy = memoryUsage.heapUsed / memoryUsage.heapTotal < 0.9
// Disk check (simplified)
const diskHealthy = true // Implement disk space check
const allHealthy = dbHealthy && memoryHealthy && diskHealthy
const status: HealthStatus = {
status: allHealthy ? 'healthy' : 'degraded',
timestamp: new Date().toISOString(),
checks: {
database: dbHealthy,
memory: memoryHealthy,
disk: diskHealthy,
},
metrics: {
uptime: process.uptime(),
memoryUsage,
responseTime: Date.now() - startTime,
},
}
res.status(allHealthy ? 200 : 503).json(status)
} catch (error) {
const status: HealthStatus = {
status: 'unhealthy',
timestamp: new Date().toISOString(),
checks: {
database: false,
memory: false,
disk: false,
},
metrics: {
uptime: process.uptime(),
memoryUsage: process.memoryUsage(),
responseTime: Date.now() - startTime,
},
}
res.status(503).json(status)
}
}
Log Analysis
Analyze application logs for issues.
#!/bin/bash
# log-analysis.sh
LOG_FILE="/var/log/app.log"
REPORT_FILE="/tmp/log-report.txt"
echo "Application Log Analysis Report" > $REPORT_FILE
echo "Generated: $(date)" >> $REPORT_FILE
echo "======================================" >> $REPORT_FILE
# Error count by type
echo "" >> $REPORT_FILE
echo "Error Count by Type:" >> $REPORT_FILE
grep -i "error" $LOG_FILE | awk '{print $3}' | sort | uniq -c | sort -nr >> $REPORT_FILE
# Response time analysis
echo "" >> $REPORT_FILE
echo "Slow Requests (>2s):" >> $REPORT_FILE
grep "response_time" $LOG_FILE | awk '$NF > 2000 {print}' | head -20 >> $REPORT_FILE
# Memory usage peaks
echo "" >> $REPORT_FILE
echo "High Memory Usage:" >> $REPORT_FILE
grep "memory_usage" $LOG_FILE | awk '$NF > 500 {print}' | tail -10 >> $REPORT_FILE
# Database connection issues
echo "" >> $REPORT_FILE
echo "Database Connection Issues:" >> $REPORT_FILE
grep -i "database.*error\|connection.*failed" $LOG_FILE | tail -10 >> $REPORT_FILE
echo "Log analysis complete. Report saved to $REPORT_FILE"
Diagnose and resolve deployment issues quickly with systematic troubleshooting approaches and diagnostic tools.