Overview
This guide covers common issues you may encounter when deploying or running the WhatsApp RAG Bot, with detailed solutions.
Webhook Problems
Webhook Verification Fails
Symptom: Meta says 'Failed to verify webhook'
Symptom: 'Unauthorized' (401) webhook error
Cause : Webhook signature verification failingFrom webhook.php:115-124: $signature = $_SERVER [ 'HTTP_X_HUB_SIGNATURE_256' ] ?? '' ;
$expected = 'sha256=' . hash_hmac ( 'sha256' , $rawBody , $appSecret );
if ( ! hash_equals ( $expected , $signature )) {
http_response_code ( 401 );
exit ( 'Unauthorized' );
}
Solution :
Verify app secret
Check .env has correct WHATSAPP_APP_SECRET from Meta Developer Console: WHATSAPP_APP_SECRET = abc123def456...
Check request headers
Log the incoming signature: error_log ( 'Received signature: ' . ( $_SERVER [ 'HTTP_X_HUB_SIGNATURE_256' ] ?? 'NONE' ));
error_log ( 'Expected signature: ' . $expected );
Temporary: Skip validation for testing
Only for debugging, never in production!
Comment out validation temporarily: // if (!hash_equals($expected, $signature)) {
// http_response_code(401);
// exit('Unauthorized');
// }
Symptom: Webhook receives messages but bot doesn't respond
Possible causes :
OpenAI API issues
Database connection problems
AI disabled for conversation
Conversation in ‘pending_human’ status
Solution :
Check logs
tail -100 logs/ $( date +%Y-%m-%d ) .log
Look for:
[ERROR] entries
OpenAI API errors
Database connection errors
Verify conversation status
SELECT phone_number, status , ai_enabled
FROM conversations
WHERE phone_number = '1234567890' ;
If status = 'pending_human' or ai_enabled = 0: UPDATE conversations
SET status = 'active' , ai_enabled = 1
WHERE phone_number = '1234567890' ;
Test OpenAI connection
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY "
API Issues
OpenAI API Errors
Insufficient Funds / Quota Exceeded
Symptom : Bot stops responding, logs show INSUFFICIENT_FUNDSFrom webhook.php:22-37, the bot automatically detects and tracks this: function handleInsufficientFunds ( $db , $e ) {
if ( strpos ( $e -> getMessage (), 'INSUFFICIENT_FUNDS' ) !== false ) {
$db -> query (
" INSERT INTO settings (setting_key, setting_value)
VALUES ('openai_status', 'insufficient_funds')
ON DUPLICATE KEY UPDATE setting_value = 'insufficient_funds'" ,
[]
);
return true ;
}
return false ;
}
Solution :
Check OpenAI account
Log in to platform.openai.com
Go to Settings > Billing
Verify account has credits
Add payment method if needed
Reset status in database
After adding credits: UPDATE settings
SET setting_value = 'active'
WHERE setting_key = 'openai_status' ;
Monitor usage
Check OpenAI usage: SELECT COUNT ( * ) as message_count
FROM messages
WHERE sender_type = 'bot'
AND created_at >= DATE_SUB( NOW (), INTERVAL 1 DAY );
Symptom : 401 Unauthorized from OpenAISolution :
Verify API key format
# Correct format
OPENAI_API_KEY = sk-proj-xxxxxxxxxxxxxxxxxxxxx
# NOT (old format)
OPENAI_API_KEY = sk-xxxxxxxxxxxxxxxxxxxxx
Test manually
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "test"}],
"max_tokens": 10
}'
Symptom : 429 Too Many RequestsSolution :
Check rate limits
OpenAI rate limits vary by tier:
Free tier: Very limited
Tier 1: 3,500 RPM (requests per minute)
Tier 2+: Higher limits
Implement request queuing
Add delays between requests: // In OpenAIService.php
sleep ( 1 ); // Wait 1 second between requests
Use embedding cache
The bot already caches embeddings in query_embedding_cache table: SELECT COUNT ( * ) FROM query_embedding_cache;
SELECT AVG (hit_count) as avg_reuse FROM query_embedding_cache;
WhatsApp API Errors
Symptom : Bot can’t send messages, 190 error from WhatsApp APISolution :
Regenerate access token
Go to developers.facebook.com
Open your WhatsApp app
Go to WhatsApp > API Setup
Generate new token
Update .env:
WHATSAPP_ACCESS_TOKEN = EAAxxxxxxxxxxxxx
Check token expiration
Temporary tokens expire in 24 hours. Use system user token for permanent access.
Symptom : First message to user fails with template errorNote :
This bot sends text messages, not template messages. Ensure you’re not triggering template requirements.Solution :
User must message you first (user-initiated conversation)
Or use approved message templates for business-initiated messages
Database Issues
Connection Problems
Can't connect to MySQL server
Symptom : SQLSTATE[HY000] [2002] Connection refusedSolution :
Verify MySQL is running
# Check status
sudo systemctl status mysql
# or
mysqladmin ping
# Start if stopped
sudo systemctl start mysql
Check credentials
DB_HOST = localhost
DB_PORT = 3306
DB_NAME = whatsapp_rag_bot
DB_USER = correct_user
DB_PASSWORD = correct_password
Test connection manually
mysql -h localhost -u your_user -p whatsapp_rag_bot
Check MySQL user permissions
SHOW GRANTS FOR 'your_user' @ 'localhost' ;
-- If needed, grant permissions:
GRANT ALL PRIVILEGES ON whatsapp_rag_bot. * TO 'your_user' @ 'localhost' ;
FLUSH PRIVILEGES;
Symptom : SQLSTATE[HY000] [1045] Access deniedSolution :-- Create user with correct permissions
CREATE USER ' whatsapp_user '@ 'localhost' IDENTIFIED BY 'secure_password' ;
GRANT ALL PRIVILEGES ON whatsapp_rag_bot. * TO 'whatsapp_user' @ 'localhost' ;
FLUSH PRIVILEGES;
Update .env with these credentials.
Symptom : Table 'whatsapp_rag_bot.documents' doesn't existSolution :# Re-import schema
mysql -u root -p whatsapp_rag_bot < database/schema.sql
# Verify tables
mysql -u root -p whatsapp_rag_bot -e "SHOW TABLES;"
Symptom : Bot responses are slow, especially with many documentsSolution :
Add missing indexes
-- Check existing indexes
SHOW INDEX FROM vectors;
-- Add if missing
CREATE INDEX idx_document_id ON vectors(document_id);
CREATE INDEX idx_created_at ON vectors(created_at);
Optimize tables
OPTIMIZE TABLE vectors;
OPTIMIZE TABLE messages;
OPTIMIZE TABLE documents;
Monitor query performance
-- Enable slow query log
SET GLOBAL slow_query_log = 'ON' ;
SET GLOBAL long_query_time = 2 ;
-- Check slow queries
SELECT * FROM mysql . slow_log ORDER BY start_time DESC LIMIT 10 ;
File Upload Issues
Symptom : Can’t upload PDF/DOCX files through admin panelSolution :
Check file size limits
From .htaccess: php_value upload_max_filesize 10M
php_value post_max_size 10M
Also check php.ini: upload_max_filesize = 10M
post_max_size = 10M
Verify directory permissions
chmod 755 uploads/
chown www-data:www-data uploads/
# Test write access
sudo -u www-data touch uploads/test.txt
Audio transcription fails
Symptom : Voice messages not transcribedFrom webhook.php:225-259, audio processing: $audioContent = $whatsapp -> downloadMedia ( $messageData [ 'audio_id' ]);
// ... save to uploads/audios/ ...
$transcription = $openai -> transcribeAudio ( $audioContent , 'audio.ogg' );
Solution :
Check uploads/audios/ exists
mkdir -p uploads/audios
chmod 755 uploads/audios
Verify OpenAI Whisper access
curl https://api.openai.com/v1/audio/transcriptions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: multipart/form-data" \
-F model="whisper-1" \
-F file="@test.ogg"
Check audio format support
WhatsApp sends OGG Opus format. Ensure OpenAI accepts it.
Logging and Debugging
Enable Debug Mode
Check PHP error logs
# Find PHP error log location
php -i | grep error_log
# View errors
tail -f /var/log/php_errors.log
Application logs
From src/Core/Logger.php, logs are written to logs/YYYY-MM-DD.log: # View today's log
tail -100 logs/ $( date +%Y-%m-%d ) .log
# Follow in real-time
tail -f logs/ $( date +%Y-%m-%d ) .log
# Search for errors
grep ERROR logs/ * .log
# Count errors by date
for file in logs/*.log ; do
echo " $file : $( grep -c ERROR $file )"
done
Common Log Messages
Normal Operation
OpenAI Issues
Database Issues
Webhook Issues
[ 2026-03-06 14:30:22 ] [INFO] Webhook received { "type" : "text" , "from_hash" : "abc123def456" }
[ 2026-03-06 14:30:23 ] [INFO] Calendar intent detection { "intent" : "schedule" , "confidence" : 0 . 85 }
[ 2026-03-06 14:30:24 ] [INFO] RAG response generated { "confidence" : 0 . 92 , "sources" : 3 }
Add Custom Logging
use App\Core\ Logger ;
$logger = new Logger ( __DIR__ . '/logs' );
// Log levels
$logger -> info ( 'User action' , [ 'user_id' => 123 ]);
$logger -> warning ( 'Unusual activity' , [ 'ip' => $_SERVER [ 'REMOTE_ADDR' ]]);
$logger -> error ( 'Critical failure' , [ 'error' => $e -> getMessage ()]);
$logger -> debug ( 'Variable dump' , [ 'data' => $someVariable ]);
Permission Errors
Symptom : No log files created, or permission denied errorsSolution :# Fix ownership
chown -R www-data:www-data logs/
# Fix permissions
chmod 755 logs/
# Verify
ls -la logs/
Symptom : Can access .env directly, or rewrites don’t workSolution :
Verify mod_rewrite enabled
# Apache
a2enmod rewrite
sudo systemctl restart apache2
# Check
apache2ctl -M | grep rewrite
Check AllowOverride
In Apache virtual host or main config: < Directory /var/www/html >
AllowOverride All
</ Directory >
Classic Bot Mode Issues
Classic bot not responding
Symptom : In classic mode, bot doesn’t follow flow nodesSolution :
Verify bot mode setting
SELECT setting_value FROM settings WHERE setting_key = 'bot_mode' ;
-- Should return: 'classic'
-- If not:
UPDATE settings SET setting_value = 'classic' WHERE setting_key = 'bot_mode' ;
Check flow nodes exist
SELECT COUNT ( * ) FROM flow_nodes WHERE is_active = 1 ;
-- Should be > 0
-- View root node:
SELECT * FROM flow_nodes WHERE is_root = 1 LIMIT 1 ;
Test flow matching
-- Check trigger keywords
SELECT name , trigger_keywords FROM flow_nodes WHERE is_active = 1 ;
Calendar Integration Issues
Symptom : Can’t create appointmentsSolution :
Verify calendar is enabled
SELECT setting_value FROM settings WHERE setting_key = 'calendar_enabled' ;
-- Should return: 'true'
Check Google OAuth credentials
SELECT access_token, refresh_token, calendar_id
FROM google_oauth_credentials
WHERE id = 1 ;
All should be non-empty.
Test Google Calendar API
curl "https://www.googleapis.com/calendar/v3/calendars/primary/events" \
-H "Authorization: Bearer $ACCESS_TOKEN "
Emergency Reset
Use only as last resort. This will clear all conversations and messages.
-- Reset conversations
TRUNCATE TABLE messages;
TRUNCATE TABLE conversations;
TRUNCATE TABLE calendar_flow_state;
TRUNCATE TABLE classic_flow_sessions;
-- Reset OpenAI status
UPDATE settings SET setting_value = 'active' WHERE setting_key = 'openai_status' ;
-- Clear embedding cache
TRUNCATE TABLE query_embedding_cache;
Getting Help
Check Logs First tail -100 logs/ $( date +%Y-%m-%d ) .log
Test Components
Test OpenAI API directly
Test WhatsApp API directly
Test database connection
-- Message volume
SELECT DATE (created_at) as date , COUNT ( * ) as count
FROM messages
GROUP BY DATE (created_at)
ORDER BY date DESC
LIMIT 7 ;
-- Average response confidence
SELECT AVG (confidence_score) as avg_confidence
FROM messages
WHERE sender_type = 'bot' AND confidence_score IS NOT NULL ;
-- Active conversations
SELECT COUNT ( * ) FROM conversations WHERE status = 'active' ;
-- Embedding cache hit rate
SELECT
COUNT ( * ) as total_queries,
SUM (hit_count) as total_hits,
AVG (hit_count) as avg_hits_per_query
FROM query_embedding_cache;
Preventive Maintenance
Daily tasks
Monitor log files for errors
Check disk space
Verify webhook is responding
Weekly tasks
Review OpenAI usage and costs
Check database size and optimize if needed
Rotate old logs (30+ days)
Monthly tasks
Update dependencies: composer update
Review and update flow nodes
Test disaster recovery (backup restore)
Review security updates