The django.db.utils.OperationalError: (1060, "Duplicate column name '...'") error means Django’s migration system tried to add a column to a database table that already contains a column with that exact name. This usually happens when a migration is run multiple times, or when the database schema is out of sync with Django’s migration history.

Here are the most common reasons this happens and how to fix them:

1. You’ve manually applied a migration or modified the database directly.

  • Diagnosis: Check your database schema directly (e.g., using psql or mysql client, or a GUI tool like pgAdmin/DBeaver). See if the column in question actually exists in the table. Also, look at your Django django_migrations table. Does the migration that should have created this column show as applied? If it does, and the column is missing, you might have a desync. If the column is present, but the migration isn’t marked as applied, that’s a classic cause.
  • Fix (if column exists, migration not applied): You can manually tell Django that the migration is already done. Find the migration file that should have created the column (e.g., 0005_add_my_field.py). Then, run:
    python manage.py migrate --fake <app_name> <migration_name>
    
    For example, if the app is myapp and the migration is 0005_add_my_field, you’d run:
    python manage.py migrate --fake myapp 0005_add_my_field
    
    This marks the migration as applied in the django_migrations table without actually running the SQL, effectively syncing Django’s state with the database.
  • Why it works: This command updates Django’s internal record of applied migrations to match the reality of the database schema, preventing Django from trying to re-apply the same change.

2. You’ve accidentally run migrate twice in quick succession, or a previous migration failed midway.

  • Diagnosis: Similar to the above, check if the column exists in the database. If it does, and you know you ran migrate and it failed, or you ran it twice, this is likely the culprit. Look at the django_migrations table to see if the problematic migration is marked as applied.
  • Fix: If the column exists and the migration is marked as applied, you’re likely good to go. If the column exists but the migration is not marked as applied, use the --fake command from point 1. If the column doesn’t exist and the migration is marked as applied, this is a trickier desync. You might need to manually create the column (if it’s safe to do so without data loss) and then use --fake to mark the migration as applied.
  • Why it works: The --fake flag is the key to re-aligning Django’s migration state with the actual database schema when an operation has already occurred but wasn’t recorded correctly.

3. You’ve reset your database or used a backup that doesn’t match your migration history.

  • Diagnosis: If you’ve dropped and recreated your database, or restored from a backup, your django_migrations table might be empty or incomplete, while your database tables might have some schema elements from previous states. Check the database schema for the column and check django_migrations for the relevant migration’s status.
  • Fix: The safest approach here is often to reset your migrations and reapply them carefully.
    1. Delete all migration files in your app(s) except __init__.py.
    2. Clear the django_migrations table in your database (e.g., DELETE FROM django_migrations;). Be extremely careful with this step, especially in production.
    3. Run python manage.py makemigrations to regenerate all migration files.
    4. Run python manage.py migrate to reapply all migrations from scratch.
  • Why it works: This process reconstructs Django’s migration history and applies it cleanly to the database, ensuring everything is in sync from a known good state.

4. Multiple developers working on the same project with conflicting migration files.

  • Diagnosis: If you pull code from version control and a migration file for a column already exists in the database (perhaps created by another developer’s earlier, un-merged migration), you’ll hit this. Check the database schema and the migration files in your project.
  • Fix:
    1. Identify the migration that’s trying to add the duplicate column.
    2. Check if that column already exists in the database.
    3. If it exists, and the migration is not yet applied, use python manage.py migrate --fake <app_name> <migration_name>.
    4. If it exists, and the migration is already applied (and this is a new error), there’s a deeper desync. You might need to revert the problematic migration, ensure the column exists, and then re-apply. Or, if the migration is genuinely redundant, you might be able to mark it as faked.
    5. If the migration file is a duplicate or conflicts with another, you might need to coordinate with the other developer to decide which migration to keep and ensure only one is applied. You might need to delete one of the conflicting migration files (after ensuring the changes are captured elsewhere or already applied).
  • Why it works: This requires careful coordination. The --fake command is a tool to bridge gaps, but fundamentally, you need a single, agreed-upon migration history.

5. You’ve used a third-party app’s migrations and then modified their models or migrations manually.

  • Diagnosis: This error can occur if you’ve edited the models or migration files of an installed third-party app (like Django REST Framework, Celery, etc.) and then tried to run your own migrations. The third-party app’s migration might try to add a column that your manual changes have already created.
  • Fix: Do NOT directly edit third-party app migrations. If you need to add fields to models provided by a third-party app, create your own migration in your app that depends on the third-party app’s migration and adds the field. If you’ve already made changes:
    1. Review the specific migration causing the error.
    2. Check if the column already exists in the database.
    3. If it exists, and the migration is not applied, use python manage.py migrate --fake <third_party_app> <migration_name>.
    4. If you must alter the third-party app’s schema, it’s often cleaner to disable their migration that causes the conflict, apply your changes, and then potentially re-enable their migration (marked as fake if necessary).
  • Why it works: This preserves the integrity of third-party packages. Customizations should ideally be layered on top of existing migrations, not embedded within them.

6. Inconsistent database states between development, staging, and production.

  • Diagnosis: This is a meta-level issue. If you’ve developed a feature locally, created migrations, but then deployed to staging or production where the database schema is different (perhaps due to manual changes or a different migration history), you’ll see this.
  • Fix: The most robust solution is to have a clear migration strategy.
    1. Generate migrations in your development environment.
    2. Test migrations thoroughly on a staging environment that closely mirrors production.
    3. Use database diffing tools (like django-migration-checker or schema comparison tools) to verify that your database schema matches your intended state before deploying.
    4. If a desync is found, use the --fake command or a full migration reset as described in previous points, depending on the severity and origin of the desync.
  • Why it works: Proactive checking and consistent application of migrations across environments prevents unexpected schema conflicts during deployment.

After fixing the immediate "Column Already Exists" error, the next common issue you might encounter is django.db.utils.OperationalError: (1068, "Multiple primary key defined") if you’ve accidentally tried to define primary keys in multiple places.

Want structured learning?

Take the full Django course →