WhatsApp API Error Handling: Troubleshooting
Panduan troubleshooting error WhatsApp API. Common errors, solutions, dan best practices. Developer debugging guide!
Error itu pasti terjadi!
Yang penting adalah bagaimana handle error dengan baik supaya aplikasi tetap reliable.
Common Errors & Solutions
1. Connection Errors
Error: Connection closed
Error: Connection lost
Error: Timed outPenyebab:
- Internet tidak stabil
- WhatsApp server down
- Session expired
Solusi:
javascript
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update;
if (connection === 'close') {
const statusCode = lastDisconnect?.error?.output?.statusCode;
// Auto reconnect kecuali logged out
if (statusCode !== DisconnectReason.loggedOut) {
console.log('Reconnecting in 5 seconds...');
setTimeout(() => startBot(), 5000);
}
}
});2. Authentication Errors
Error: Not authorized
Error: Invalid credentials
Error: Session expiredPenyebab:
- Session invalid
- Logged out dari HP
- Auth file corrupt
Solusi:
javascript
// Delete auth dan re-scan
const fs = require('fs');
function resetAuth() {
if (fs.existsSync('./auth_info')) {
fs.rmSync('./auth_info', { recursive: true });
}
console.log('Auth reset. Scan QR lagi.');
startBot();
}
// Trigger saat auth error
if (statusCode === DisconnectReason.loggedOut) {
resetAuth();
}3. Rate Limit Errors
Error: Rate limit exceeded
Error: Too many requests
Error Code: 80007Penyebab:
- Kirim terlalu cepat
- Volume terlalu tinggi
Solusi:
javascript
const queue = [];
let isProcessing = false;
async function sendWithQueue(to, message) {
queue.push({ to, message });
processQueue();
}
async function processQueue() {
if (isProcessing || queue.length === 0) return;
isProcessing = true;
while (queue.length > 0) {
const { to, message } = queue.shift();
try {
await sock.sendMessage(to, message);
} catch (error) {
if (isRateLimitError(error)) {
// Put back in queue and wait
queue.unshift({ to, message });
await sleep(30000); // Wait 30 seconds
}
}
await sleep(3000); // 3 second delay between messages
}
isProcessing = false;
}4. Invalid Number
Error: Number not registered on WhatsApp
Error: Invalid phone number formatPenyebab:
- Nomor tidak terdaftar di WA
- Format nomor salah
Solusi:
javascript
async function validateNumber(phone) {
try {
const [result] = await sock.onWhatsApp(phone);
return result?.exists || false;
} catch {
return false;
}
}
async function safeSend(phone, message) {
const isValid = await validateNumber(phone);
if (!isValid) {
console.log(`Invalid number: ${phone}`);
return { success: false, reason: 'invalid_number' };
}
await sock.sendMessage(`${phone}@s.whatsapp.net`, message);
return { success: true };
}5. Media Errors
Error: Media upload failed
Error: File too large
Error: Unsupported media typePenyebab:
- File terlalu besar
- Format tidak didukung
- Upload timeout
Solusi:
javascript
const MAX_FILE_SIZE = 16 * 1024 * 1024; // 16MB
async function sendMediaSafe(to, filePath, type) {
const stats = fs.statSync(filePath);
if (stats.size > MAX_FILE_SIZE) {
throw new Error('File too large. Max 16MB.');
}
const supportedTypes = {
image: ['.jpg', '.jpeg', '.png', '.gif', '.webp'],
video: ['.mp4', '.3gp'],
audio: ['.mp3', '.ogg', '.m4a'],
document: ['.pdf', '.doc', '.docx', '.xls', '.xlsx']
};
const ext = path.extname(filePath).toLowerCase();
if (!supportedTypes[type]?.includes(ext)) {
throw new Error(`Unsupported ${type} format: ${ext}`);
}
// Send with retry
return await sendWithRetry(to, {
[type]: fs.readFileSync(filePath)
});
}6. Cloud API Errors
json
{
"error": {
"message": "(#131030) Recipient phone number not in allowed list",
"code": 131030
}
}Common Cloud API Error Codes:
| Code | Meaning | Solution |
|---|---|---|
| 131030 | Not in allowed list | Add to test numbers |
| 131031 | Business eligibility | Verify business |
| 131047 | Re-engagement required | Send template first |
| 131051 | Unsupported message | Check message format |
| 80007 | Rate limit | Slow down |
| 190 | Access token expired | Refresh token |
Error Handling Pattern
Global Error Handler:
javascript
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
// Log to monitoring service
logError(error);
// Don't exit, try to recover
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection:', reason);
logError(reason);
});Try-Catch Wrapper:
javascript
async function safeExecute(fn, fallback) {
try {
return await fn();
} catch (error) {
console.error('Error:', error.message);
logError(error);
return fallback;
}
}
// Usage
const response = await safeExecute(
() => getAIResponse(message),
'Maaf, terjadi kesalahan. Coba lagi nanti.'
);Retry with Backoff:
javascript
async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
const delay = baseDelay * Math.pow(2, attempt - 1);
console.log(`Attempt ${attempt} failed. Retrying in ${delay}ms...`);
await sleep(delay);
}
}
}
// Usage
await retryWithBackoff(() => sock.sendMessage(to, message));Logging Best Practices
javascript
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// Log errors with context
function logError(error, context = {}) {
logger.error({
message: error.message,
stack: error.stack,
...context,
timestamp: new Date().toISOString()
});
}
// Usage
try {
await sendMessage(to, message);
} catch (error) {
logError(error, { to, messageType: 'text' });
}Health Monitoring
javascript
const healthStatus = {
connected: false,
lastMessage: null,
errorCount: 0,
uptime: Date.now()
};
sock.ev.on('connection.update', (update) => {
healthStatus.connected = update.connection === 'open';
});
sock.ev.on('messages.upsert', () => {
healthStatus.lastMessage = Date.now();
});
// Health check endpoint
app.get('/health', (req, res) => {
const healthy = healthStatus.connected &&
(Date.now() - healthStatus.lastMessage < 300000); // 5 min
res.status(healthy ? 200 : 503).json({
status: healthy ? 'healthy' : 'unhealthy',
...healthStatus,
uptime: Math.floor((Date.now() - healthStatus.uptime) / 1000)
});
});FAQ
Bagaimana debug error yang tidak jelas?
Enable verbose logging, check network, dan test dengan minimal code untuk isolate issue.
Kapan harus restart vs reconnect?
Reconnect untuk connection issues. Restart untuk auth issues atau memory leaks.
Perlu monitoring?
Ya! Gunakan tools seperti PM2, Sentry, atau custom health checks.
Kesimpulan
Good error handling = Reliable bot!
| Practice | Benefit |
|---|---|
| Try-catch | Prevent crashes |
| Retry logic | Handle transient errors |
| Logging | Debug & audit |
| Monitoring | Proactive alerts |
Expect errors, handle gracefully!