Troubleshooting#
This guide covers common issues and their solutions when using django-phone-verify.
Installation Issues#
ImportError: No module named ‘twilio’ or ‘nexmo’#
Problem: You get an import error when the backend tries to load.
Solution: Install the required backend package:
# For Twilio
pip install django-phone-verify[twilio]
# For Nexmo
pip install django-phone-verify[nexmo]
# For both
pip install django-phone-verify[all]
The core package doesn’t include SMS provider libraries by default to keep it lightweight.
Configuration Errors#
ImproperlyConfigured: Please define PHONE_VERIFICATION in settings#
Problem: Django can’t find the PHONE_VERIFICATION configuration.
Solution: Add the configuration dictionary to your settings.py:
PHONE_VERIFICATION = {
"BACKEND": "phone_verify.backends.twilio.TwilioBackend",
"OPTIONS": {
"SID": "your-sid",
"SECRET": "your-secret",
"FROM": "+15551234567",
},
"TOKEN_LENGTH": 6,
"MESSAGE": "Your code is {security_code}",
"APP_NAME": "MyApp",
"SECURITY_CODE_EXPIRATION_SECONDS": 3600,
"VERIFY_SECURITY_CODE_ONLY_ONCE": False,
}
ImproperlyConfigured: Please specify following settings#
Problem: Some required settings keys are missing.
Solution: Ensure all required keys are present:
BACKENDOPTIONSTOKEN_LENGTHMESSAGEAPP_NAMESECURITY_CODE_EXPIRATION_SECONDSVERIFY_SECURITY_CODE_ONLY_ONCE
Even if you don’t need to customize them, you must include all keys with at least their default values.
SMS Sending Issues#
SMS Not Being Received#
Possible Causes and Solutions:
Wrong phone number format
Ensure phone numbers are in E.164 format (
+<country_code><number>):# ✅ Correct "+14155551234" # ❌ Incorrect "4155551234" "(415) 555-1234"
Twilio/Nexmo credentials are incorrect
Verify your credentials in the provider’s dashboard. Test with a simple script:
from twilio.rest import Client client = Client("your_sid", "your_secret") message = client.messages.create( body="Test", from_="+15551234567", to="+15559876543" ) print(message.sid)
Phone number not verified (Sandbox mode)
If you’re using a trial account, you may need to verify recipient numbers in your provider dashboard first.
Rate limiting
Check if your SMS provider is rate-limiting your requests. Implement exponential backoff or contact your provider.
Network/Firewall issues
Ensure your server can make outbound HTTPS requests to your SMS provider’s API.
TwilioRestException or Nexmo Client Errors#
Problem: SMS sending raises an exception from the provider.
Solution:
Check the exception message for specific error codes
Verify account balance/credits
Check that your
FROMnumber is SMS-capableReview provider-specific error documentation: - Twilio Error Codes - Vonage Error Codes
Verification Issues#
“Security code is not valid”#
Possible Causes:
Typo in the code - User entered wrong code
Code expired - Check
SECURITY_CODE_EXPIRATION_SECONDSsettingDatabase was cleared - Security codes were deleted
Different phone number - Verification and code request used different numbers
Solution:
Implement a “resend code” feature
Increase expiration time if appropriate
Log verification attempts to debug
“Session Token mis-match”#
Problem: The session token provided doesn’t match the one in the database.
Causes:
Session token not stored correctly on the client side
Multiple registration attempts - Old token being used with new code
Token corruption during transmission
Solution:
Ensure client stores the full session token from
/api/phone/registerUse the same token for verification that was returned during registration
Check for any string truncation or encoding issues
“Security code has expired”#
Problem: User took too long to enter the code.
Solution:
Increase expiration time:
PHONE_VERIFICATION = { ... "SECURITY_CODE_EXPIRATION_SECONDS": 7200, # 2 hours instead of 1 }
Implement resend functionality - Let users request a new code
Show countdown timer in your UI to indicate remaining time
“Security code is already verified”#
Problem: Code was already used and VERIFY_SECURITY_CODE_ONLY_ONCE is True.
Causes:
Double submission - User clicked verify button twice
Code reuse attempt - User trying to verify multiple times
Solution:
This is expected behavior for one-time codes
If you need reusable codes, set
VERIFY_SECURITY_CODE_ONLY_ONCEtoFalseImplement proper form/button disabling to prevent double submission
Database Issues#
Unique Constraint Violation#
Problem: Error about unique constraint on (security_code, phone_number, session_token).
Cause: Extremely rare collision in randomly generated codes.
Solution: The library handles this by deleting old codes before creating new ones. If you’re manually creating SMSVerification objects, ensure you follow the same pattern:
from phone_verify.models import SMSVerification
# Delete old codes first
SMSVerification.objects.filter(phone_number=phone_number).delete()
# Then create new
SMSVerification.objects.create(...)
Custom Backend Issues#
Backend Not Found#
Problem: ModuleNotFoundError when loading your custom backend.
Solution:
Ensure the module path in
BACKENDsetting is correctCheck that your backend class inherits from
BaseBackendVerify the Python module is in your
PYTHONPATH
Example for a backend in myapp/backends/sms.py:
PHONE_VERIFICATION = {
"BACKEND": "myapp.backends.sms.CustomBackend",
...
}
“send_sms() missing required argument”#
Problem: Your custom backend’s send_sms method signature is incorrect.
Solution: Ensure your backend implements the required methods with correct signatures:
from phone_verify.backends.base import BaseBackend
class CustomBackend(BaseBackend):
def send_sms(self, number, message):
# number is a single phone number string
# message is the SMS content
pass
def send_bulk_sms(self, numbers, message):
# numbers is a list of phone number strings
# message is the SMS content
pass
Integration Issues#
DRF ViewSet Not Found#
Problem: 404 errors when accessing /api/phone/register or /api/phone/verify.
Solution: Ensure you’ve registered the ViewSet in your URLs:
# urls.py
from rest_framework.routers import DefaultRouter
from phone_verify.api import VerificationViewSet
router = DefaultRouter(trailing_slash=False)
router.register('phone', VerificationViewSet, basename='phone')
urlpatterns = [
path('api/', include(router.urls)),
]
Serializer Validation Fails Silently#
Problem: Validation errors not being shown to the user.
Solution: Use raise_exception=True in your views:
serializer = SMSVerificationSerializer(data=request.data)
serializer.is_valid(raise_exception=True) # This will return 400 with error details
Testing Issues#
Tests Sending Real SMS#
Problem: Your test suite is sending actual SMS messages and consuming credits.
Solution: Use a sandbox backend or mock the SMS sending:
Option 1: Sandbox Backend
# test_settings.py
PHONE_VERIFICATION = {
"BACKEND": "phone_verify.backends.twilio.TwilioSandboxBackend",
"OPTIONS": {
"SANDBOX_TOKEN": "123456", # Fixed code for tests
...
},
...
}
Option 2: Mock with pytest
from unittest.mock import patch
@patch('phone_verify.backends.twilio.TwilioBackend.send_sms')
def test_verification(mock_send_sms):
# Your test code here
mock_send_sms.assert_called_once()
Option 3: Custom Test Backend
from phone_verify.backends.base import BaseBackend
class TestBackend(BaseBackend):
def send_sms(self, number, message):
pass # No-op
def send_bulk_sms(self, numbers, message):
pass
Performance Issues#
Slow API Responses#
Problem: /api/phone/register takes too long to respond.
Causes and Solutions:
SMS provider latency - Consider sending SMS asynchronously:
from celery import shared_task from phone_verify.services import PhoneVerificationService @shared_task def send_verification_async(phone_number, security_code): service = PhoneVerificationService(phone_number) service.send_verification(phone_number, security_code)
Database queries - Ensure your database has appropriate indexes (they’re included in migrations)
Network issues - Check connectivity to your SMS provider
Too Many Database Records#
Problem: sms_verification table growing too large.
Solution: Implement a cleanup task to delete old verifications:
from django.utils import timezone
from datetime import timedelta
from phone_verify.models import SMSVerification
# Delete verifications older than 7 days
cutoff = timezone.now() - timedelta(days=7)
SMSVerification.objects.filter(created_at__lt=cutoff).delete()
Run this periodically with a cron job or Celery beat task.
Getting Help#
If your issue isn’t covered here:
Check GitHub Issues: CuriousLearner/django-phone-verify#issues
Review Recent Changes: Release Notes
Enable Debug Logging:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'phone_verify': { 'handlers': ['console'], 'level': 'DEBUG', }, }, }
Open a new issue with: - Django version - Python version -
django-phone-verifyversion - Backend being used - Full traceback - Minimal reproducible example