Skip to Content
GuidesTroubleshooting

Troubleshooting Guide

Quick Troubleshooting Common issues and solutions when using Django-CFG. Use Details to expand specific problems, or search with Ctrl+F.

Common issues and solutions when using django-cfg.

Configuration Issues

ConfigurationError: At least one database must be configured

Problem:

django_cfg.core.exceptions.ConfigurationError: At least one database must be configured

Cause: No databases defined in configuration.

Solution:

from django_cfg import DjangoConfig, DatabaseConfig class MyConfig(DjangoConfig): databases = { "default": DatabaseConfig( engine="django.db.backends.sqlite3", name="db.sqlite3", ) }

Quick Fix Django requires at least one database with the alias "default". Even if you don’t use a database, configure SQLite as a placeholder.

ConfigurationError: ‘default’ database is required

Problem:

ConfigurationError: 'default' database is required

Cause: Databases configured but no ‘default’ alias.

Solution:

databases = { "default": DatabaseConfig(...), # ← Must have 'default' "other": DatabaseConfig(...), }

Required Alias Django always requires a database with the alias "default". You can have additional databases, but "default" is mandatory.

ValidationError: SECRET_KEY must be at least 50 characters

Problem:

ValidationError: SECRET_KEY must be at least 50 characters long

Solution:

# Generate a secure secret key from django.core.management.utils import get_random_secret_key secret_key = get_random_secret_key() # Or use environment variable secret_key = "${SECRET_KEY}"

Security Critical Never use short or weak SECRET_KEY in production:

  • ❌ “changeme” - Too short and obvious
  • ❌ “django-insecure-…” - Development only
  • ✅ Generate with: python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
  • ✅ Store in environment variables, never commit to git

Extra inputs are not permitted

Problem:

pydantic_core._pydantic_core.ValidationError: Extra inputs are not permitted

Cause: Using invalid or non-existent field name in configuration.

Solution:

# Ensure you only use valid DjangoConfig fields class MyConfig(DjangoConfig): security_domains = [...] # ✅ Valid field # Check documentation for all available fields

Finding Valid Fields Check available fields in:

Import Errors

ImportError: cannot import name ‘get_current_config’

Problem:

ImportError: cannot import name 'get_current_config' from 'django_cfg.core.config'

Solution:

# Update import path from django_cfg.core import get_current_config # ✅ Correct # Or from django_cfg.core.state import get_current_config # ✅ Also correct # Not this: # from django_cfg.core.config import get_current_config # ❌ Old path

Correct Import Paths Django-CFG reorganized imports in recent versions. Always import from:

  • from django_cfg import DjangoConfig, get_current_config (recommended)
  • from django_cfg.core import DjangoConfig, get_current_config (also works)

ImportError: cannot import name ‘DjangoConfig’

Problem:

ImportError: cannot import name 'DjangoConfig'

Solution:

# Make sure django-cfg is installed (Python 3.12+ required) python3.12 -m venv .venv && source .venv/bin/activate pip3 install 'django-cfg[full]'
# Correct import from django_cfg import DjangoConfig # Or from django_cfg.core import DjangoConfig

Installation Check Verify django-cfg is installed:

pip show django-cfg # Should show package information pip list | grep django-cfg # Should list the package

Circular Import Error

Problem:

ImportError: cannot import name 'DjangoConfig' from partially initialized module 'django_cfg'

Cause: Circular import between settings and config.

Solution:

# settings.py from myproject.config import MyConfig # ✅ Import config class config = MyConfig() globals().update(config.get_all_settings()) # Don't import settings in config.py!

Circular Import Prevention Never do this:

# config.py from django.conf import settings # ❌ Creates circular import

Instead, use lazy imports or dependency injection:

# config.py def get_setting_value(): from django.conf import settings # ✅ Lazy import inside function return settings.SOME_VALUE

Database Issues

Database routing references non-existent databases

Problem:

ConfigurationError: Database routing references non-existent databases: {'analytics'}

Cause: migrate_to references database that doesn’t exist.

Solution:

databases = { "default": DatabaseConfig(...), "analytics": DatabaseConfig( ..., migrate_to="default", # ← Ensure 'default' exists ), }

Database Routing Validation Django-CFG validates that all migrate_to references point to existing databases. Common mistakes:

  • ❌ Typo in database alias: migrate_to="defualt"
  • ❌ Reference to database not in databases dict
  • ✅ Always reference existing database aliases

django.db.utils.OperationalError: FATAL: database does not exist

Problem: Database connection fails because database doesn’t exist.

Solution:

# Create the database first createdb mydb # Or configure to create automatically databases = { "default": DatabaseConfig( ..., options={"autocommit": True}, ) }

Database Creation PostgreSQL:

createdb mydb # Or with user: createdb -U myuser mydb

MySQL:

mysql -u root -p -e "CREATE DATABASE mydb;"

SQLite: Django creates SQLite databases automatically if they don’t exist.

Migrations not running on correct database

Problem: Migrations run on wrong database in multi-database setup.

Solution:

# Use migrate_to to control where migrations run databases = { "default": DatabaseConfig(...), "analytics": DatabaseConfig( ..., migrate_to="default", # Migrations run here ), } # Then run python manage.py migrate # Migrates default only python manage.py migrate_all # Migrates all with routing

Multi-Database Migration Control The migrate_to parameter controls where migrations execute:

  • Not set: Migrations run on the database itself
  • Set to another db: Migrations run on the target database
  • Common pattern: All migrations on default, data on separate databases

See Multi-Database Guide for detailed patterns.

CORS Issues

CORS header ‘Access-Control-Allow-Origin’ missing

Problem: Browser console shows CORS error in production.

Cause: Production requires security_domains configuration.

Solution:

# Production: Configure security_domains security_domains = [ "frontend.example.com", # ✅ Any format works "https://api.example.com", # ✅ With protocol "staging.example.com:3000", # ✅ With port ] # Development: No configuration needed! # debug=True automatically enables CORS_ALLOW_ALL_ORIGINS

Environment-Aware CORS Configuration Django-CFG automatically configures CORS based on environment:

Development Mode (debug=True or no security_domains):

  • CORS_ALLOW_ALL_ORIGINS = True - Fully open
  • ALLOWED_HOSTS = ['*'] - All hosts accepted
  • ✅ Docker IPs work automatically
  • ✅ No configuration needed!

Production Mode (when security_domains set):

  • CORS_ALLOWED_ORIGINS - Generated from security_domains
  • CORS_ALLOW_CREDENTIALS = True - Credentials enabled
  • ALLOWED_HOSTS - Strict whitelist
  • ✅ Auto-normalized from any domain format
  • ✅ CORS middleware auto-inserted

CORS allows all origins in production

Problem: CORS_ALLOW_ALL_ORIGINS = True in production.

Cause: Not setting security_domains in production configuration.

Solution:

# REQUIRED in production - set security_domains security_domains = [ "example.com", "api.example.com", ] # This automatically switches to strict whitelist mode

Security Critical: CORS Misconfiguration Django-CFG behavior:

  • Development (debug=True or no security_domains) → CORS fully open
  • 🔒 Production (when security_domains set) → Strict whitelist only

Allowing all origins in production is a critical security vulnerability:

  • 🔒 CSRF attacks - Any site can make requests to your API
  • 🔒 Data theft - Malicious sites can steal user data
  • 🔒 Session hijacking - Attackers can exploit user sessions

Production checklist:

  • REQUIRED: Set security_domains with production domains
  • ✅ Use HTTPS domains (handled by reverse proxy)
  • ✅ Include only trusted domains
  • ✅ Set debug = False
  • ❌ Never leave security_domains empty/None in production

Example validation:

if env.env_mode == "production": if not config.security_domains: raise ValueError("CRITICAL: security_domains required in production!")

Static Files Issues

Static files not found (404)

Problem: Static files return 404 in production.

Solution:

# Collect static files python manage.py collectstatic --noinput # Ensure WhiteNoise is configured (automatic in django-cfg) # Check STATIC_ROOT python manage.py show_config | grep STATIC

WhiteNoise Auto-Configuration Django-CFG automatically configures WhiteNoise for static file serving:

  • Middleware added - WhiteNoise middleware inserted
  • STATIC_ROOT set - Points to staticfiles/ directory
  • Compression enabled - GZip compression for performance
  • Caching configured - Far-future cache headers

Production checklist:

  1. Run collectstatic before deployment
  2. Set STATIC_ROOT in environment if needed
  3. Verify static files exist in STATIC_ROOT

Static files not updating

Problem: CSS/JS changes not reflected.

Solution:

# Clear browser cache # Or bust cache with versioning # In development, ensure DEBUG=True debug = True

Cache Busting Strategies Development:

  • Hard refresh browser: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
  • Disable cache in DevTools (Network tab → “Disable cache”)
  • Set DEBUG = True to disable aggressive caching

Production:

  • Use Django’s ManifestStaticFilesStorage (automatic with WhiteNoise)
  • Files get hash suffix: style.cssstyle.a4b3c2d1.css
  • Changes create new hash → browser fetches new file

Background Tasks Issues

Tasks not being processed

Problem: Tasks enqueued but never execute.

Cause: Worker not running.

Solution:

# Start ReArq worker rearq main:rearq worker # Or with specific queues rearq main:rearq worker --queues default high_priority # Check worker status rearq main:rearq info

Worker Must Be Running ReArq requires a separate worker process to execute tasks:

  • Common mistake: Enqueueing tasks without running worker
  • Development: Run rearq main:rearq worker in separate terminal
  • Production: Use process manager (systemd, supervisor, Docker)

Check if worker is running:

ps aux | grep rearq_worker # Should show running process

Redis connection refused

Problem:

redis.exceptions.ConnectionError: Error 61 connecting to localhost:6379. Connection refused.

Cause: Redis not running.

Solution:

# Start Redis redis-server # Or use Docker docker run -d -p 6379:6379 redis # Verify connection redis-cli ping # Should return PONG

Redis Installation & Setup Install Redis:

  • macOS: brew install redis && brew services start redis
  • Ubuntu: sudo apt install redis-server && sudo systemctl start redis
  • Docker: docker run -d -p 6379:6379 redis

Verify Redis:

redis-cli ping # Should return: PONG redis-cli info | grep uptime # Show uptime

Configure custom Redis URL:

# In config.py redis_url: str = "redis://localhost:6379/0"

Tasks stuck in queue

Problem: Tasks enqueued but status shows “pending” forever.

Solution:

# Check worker logs rearq main:rearq worker --verbose # Clear stuck tasks rearq main:rearq flush # Restart worker # Kill existing worker and start fresh

Debugging Stuck Tasks Common causes of stuck tasks:

  1. Worker crashed - Check logs for exceptions
  2. Task timeout - Increase timeout in task config
  3. Deadlock - Task waiting for another task
  4. Queue mismatch - Task sent to queue worker isn’t watching

Debug steps:

# 1. Check worker is processing rearq main:rearq worker --verbose # Watch logs # 2. Check Redis has messages redis-cli LLEN "arq:queue:default" # Queue length # 3. Manually retry task rearq main:rearq retry <task_id>

Email Issues

Email not sending

Problem: Emails not being sent/received.

Solution:

# Check email configuration from django.core.mail import send_mail send_mail( 'Test Subject', 'Test message', '[email protected]', ['[email protected]'], fail_silently=False, # ← Show errors ) # Or use test command python manage.py test_email to@example.com

Email Testing & Debugging Development:

  • Use console backend: backend="django.core.mail.backends.console.EmailBackend"
  • Emails print to console instead of sending

Testing:

# In config.py email = EmailConfig( backend="django.core.mail.backends.console.EmailBackend", # Development ) # Or use file backend email = EmailConfig( backend="django.core.mail.backends.filebased.EmailBackend", file_path="tmp/emails", # Emails saved as files )

Check configuration:

python manage.py show_config | grep EMAIL

SMTP authentication failed

Problem:

SMTPAuthenticationError: (535, b'5.7.8 Authentication failed')

Solution:

# Verify credentials email = EmailConfig( backend="django.core.mail.backends.smtp.EmailBackend", host="smtp.gmail.com", port=587, use_tls=True, user="${EMAIL_USER}", # Check this password="${EMAIL_PASSWORD}", # Check this ) # For Gmail, use App Password (not regular password)

Gmail App Passwords Required Gmail requires App Passwords for SMTP:

  1. Enable 2-Factor Authentication on Google account
  2. Go to Google Account → Security → App Passwords
  3. Generate new app password for “Mail”
  4. Use generated password (16 chars, no spaces)

Common SMTP configurations:

# Gmail email = EmailConfig( host="smtp.gmail.com", port=587, use_tls=True, ) # Outlook/Office365 email = EmailConfig( host="smtp.office365.com", port=587, use_tls=True, ) # Example SMTP email = EmailConfig( host="smtp.example.com", port=587, use_tls=True, user="your-username", password="your-password", )

Ngrok Issues

Ngrok tunnel not starting

Problem: runserver_ngrok fails to start tunnel.

Solution:

# Install pyngrok pip install pyngrok # Set auth token (for custom subdomain) export NGROK_AUTH_TOKEN=your_token_here # Or configure in settings ngrok = NgrokConfig( enabled=True, auth_token="${NGROK_AUTH_TOKEN}", )

Ngrok Setup Install pyngrok:

pip install pyngrok

Get auth token:

  1. Sign up at https://ngrok.com 
  2. Go to Dashboard → Auth Token
  3. Copy token and set environment variable

Configure in Django-CFG:

# config.py ngrok = NgrokConfig( enabled=True, auth_token="${NGROK_AUTH_TOKEN}", subdomain="myapp", # Optional: fixed subdomain (requires paid plan) )

Start server with ngrok:

python manage.py runserver_ngrok # Output: Ngrok tunnel: https://myapp.ngrok.io

Ngrok tunnel URL changes

Problem: Tunnel URL changes every restart (random subdomain).

Solution:

# Use custom subdomain (requires ngrok auth token) ngrok = NgrokConfig( enabled=True, auth_token="${NGROK_AUTH_TOKEN}", subdomain="myapp", # Fixed subdomain )

Ngrok Free vs Paid Free plan:

  • ✅ Random subdomain: https://abc123.ngrok.io
  • ❌ Changes on every restart
  • ✅ Good for testing webhooks

Paid plan ($8/month):

  • ✅ Custom subdomain: https://myapp.ngrok.io
  • ✅ Persistent URL across restarts
  • ✅ Multiple tunnels simultaneously

Alternatives to paid ngrok:

  • localtunnel - Free, but less stable
  • serveo - Free SSH tunneling
  • pagekite - Free tier available

Debug Tools

Using check_settings command

# Validate all Django settings python manage.py check_settings # Shows: # - Required settings present # - Security issues # - Configuration warnings

check_settings Command Django-CFG provides check_settings command to validate configuration:

  • ✅ Checks required settings (SECRET_KEY, DATABASES, etc.)
  • ✅ Validates security settings (ALLOWED_HOSTS, CORS, etc.)
  • ✅ Warns about common misconfigurations
  • ✅ Shows configuration recommendations

Example output:

✓ SECRET_KEY configured (50+ characters) ✓ Database 'default' configured ✓ ALLOWED_HOSTS configured for production ⚠ DEBUG=True in production (should be False)

Using show_config command

# Display current configuration python manage.py show_config # Show specific section python manage.py show_config --section databases python manage.py show_config --section security

show_config Options Display modes:

# Full configuration python manage.py show_config # Specific section python manage.py show_config --section databases python manage.py show_config --section security python manage.py show_config --section middleware # Sanitized output (hides secrets) python manage.py show_config --sanitize # Debug mode (verbose) python manage.py show_config --debug

Useful for:

  • Verifying configuration values
  • Debugging environment variable expansion
  • Checking middleware order
  • Validating database settings

Enable Debug Mode

# Temporary debug mode DEBUG = True startup_info_mode = StartupInfoMode.FULL # Enables: # - Detailed error pages # - Full startup information # - Template debug # - SQL query logging

Debug Mode Settings Development:

# config.py debug = True startup_info_mode = StartupInfoMode.FULL

Production:

# config.py debug = False # ← Must be False startup_info_mode = StartupInfoMode.NONE

What DEBUG=True enables:

  • Detailed error pages with full traceback
  • Template variable inspection
  • SQL query logging (performance impact)
  • Static file serving (slow, use only in dev)

Security risk in production:

  • 🔒 Exposes source code paths
  • 🔒 Shows environment variables
  • 🔒 Reveals database queries
  • 🔒 Displays sensitive settings

Debug Warnings with Traceback

Problem: You see RuntimeWarnings like:

RuntimeWarning: Accessing the database during app initialization is discouraged.

But you don’t know WHERE in your code it’s happening.

Solution: Enable debug_warnings to see full stack traceback:

config.py
from django_cfg import DjangoConfig class MyConfig(DjangoConfig): project_name: str = "My Project" # Enable warnings traceback in development debug_warnings: bool = True # ← Shows full stack trace

Via Environment Variable

export DJANGO_CFG_DEBUG_WARNINGS=1 python manage.py runserver

Example Output:

================================================================================ ⚠️ WARNING TRACEBACK (to help find the source) ================================================================================ File "/path/to/your/code/apps.py", line 42, in ready self.setup_database() File "/path/to/your/code/apps.py", line 55, in setup_database MyModel.objects.all() # ← HERE IS THE PROBLEM! ^^^^^^^^^^^^^^^^^^^^ -------------------------------------------------------------------------------- ⚠️ WARNING MESSAGE: RuntimeWarning: Accessing the database during app initialization is discouraged. To fix this warning, avoid executing queries in AppConfig.ready() or when your app modules are imported. ================================================================================

Common Issues Found Database access in AppConfig.ready():

# ❌ Bad - queries during import def ready(self): from .models import MyModel MyModel.objects.create(...) # ✅ Good - use post_migrate signal def ready(self): from django.db.models.signals import post_migrate post_migrate.connect(self.setup_data, sender=self)

Model queries at module level:

# ❌ Bad - runs during import from .models import MyModel DEFAULT_SETTINGS = MyModel.objects.first() # ✅ Good - lazy evaluation def get_default_settings(): from .models import MyModel return MyModel.objects.first()

What debug_warnings shows:

  • 📍 Full stack trace to the exact line
  • 🎯 Which app/file is causing the warning
  • 🔍 Complete call chain from Django startup
  • ⚡ Works for RuntimeWarning, DeprecationWarning, etc.

Check Django Configuration

# Run Django system checks python manage.py check # Run deployment checks python manage.py check --deploy # Check specific tag python manage.py check --tag security

Django Check Framework Available check tags:

# Security checks python manage.py check --tag security # Database checks python manage.py check --tag database # Model checks python manage.py check --tag models # Compatibility checks python manage.py check --tag compatibility # All deployment checks python manage.py check --deploy

Common issues detected:

  • Missing SECRET_KEY or weak SECRET_KEY
  • DEBUG=True in production
  • Missing ALLOWED_HOSTS
  • Insecure middleware configuration
  • Missing staticfiles configuration

Performance Issues

Settings generation slow

Problem: Application startup is slow.

Cause: Settings generated on every request (should be cached).

Solution:

# Settings are cached by default # Clear cache manually if needed config.invalidate_cache() # Or use cached property @property def my_settings(self): if not hasattr(self, '_my_settings_cache'): self._my_settings_cache = expensive_operation() return self._my_settings_cache

Configuration Caching Django-CFG automatically caches configuration:

  • Settings cached - Generated once per application lifecycle
  • Environment variables cached - Expanded once
  • Model imports cached - No repeated imports

Performance benchmarks:

  • First generation: ~50-100ms
  • Cached access: <1ms
  • No runtime overhead after startup

When to invalidate cache:

  • Environment variables changed
  • Configuration file modified
  • Dynamic settings updated

Database queries slow

Problem: Database operations are slow.

Solution:

# Enable connection pooling databases = { "default": DatabaseConfig( ..., conn_max_age=600, # Connection pooling options={ "connect_timeout": 10, }, ), } # Use database indexes # Use select_related() and prefetch_related() # Enable query logging to identify slow queries

Database Performance Optimization Connection pooling:

databases = { "default": DatabaseConfig( conn_max_age=600, # Keep connections alive for 10 minutes conn_health_checks=True, # Validate connections before use ), }

Query optimization:

# N+1 query problem - BAD for user in User.objects.all(): print(user.profile.bio) # Extra query per user # Optimized with select_related - GOOD for user in User.objects.select_related('profile'): print(user.profile.bio) # Single JOIN query

Debug slow queries:

# config.py LOGGING = { 'loggers': { 'django.db.backends': { 'level': 'DEBUG', # Log all SQL queries }, }, }

Tools for profiling:

  • django-debug-toolbar - Visual query profiler
  • django-silk - Request profiling
  • nplusone - Detect N+1 queries

Getting More Help

Enable Verbose Logging

import logging logging.basicConfig(level=logging.DEBUG) # Or configure in LOGGING LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'root': { 'handlers': ['console'], 'level': 'DEBUG', }, }

Collect Debug Information

When reporting issues, include:

# Django-cfg version pip show django-cfg # Django version python -m django --version # Python version python --version # Configuration (sanitized) python manage.py show_config --sanitize # Django checks python manage.py check --deploy # Full traceback # (Copy entire error with traceback)

Community Support

  • GitHub Issues: Report bugs
  • Discussions: Ask questions
  • Stack Overflow: Tag with django-cfg
  • Discord/Slack: Real-time help

Professional Support

For enterprise customers:

  • Priority bug fixes
  • Migration assistance
  • Custom feature development
  • Architecture review

Common Patterns

Development vs Production

# Use environment-specific configuration from django_cfg import DjangoConfig, StartupInfoMode # Development class DevelopmentConfig(DjangoConfig): debug: bool = True startup_info_mode: str = StartupInfoMode.FULL # Production class ProductionConfig(DjangoConfig): debug: bool = False startup_info_mode: str = StartupInfoMode.NONE security_domains: list[str] = ["example.com"]

Testing Configuration

# Test-specific settings from django_cfg import DjangoConfig, DatabaseConfig, EmailConfig class TestConfig(DjangoConfig): debug: bool = True databases: dict = { "default": DatabaseConfig( engine="django.db.backends.sqlite3", name=":memory:", ) } email: EmailConfig = EmailConfig( backend="django.core.mail.backends.locmem.EmailBackend", )

Environment Variables

# Load from .env file from dotenv import load_dotenv load_dotenv() # Use in configuration secret_key = "${SECRET_KEY}" databases = { "default": DatabaseConfig( name="${DATABASE_NAME}", user="${DATABASE_USER}", password="${DATABASE_PASSWORD}", ) }

Next Steps

Last updated on