Fix Django NodeNotFoundError: Migration Dependencies Reference Nonexistent Parent Node

Fix the Django NodeNotFoundError saying migration dependencies reference a nonexistent parent node: restore deleted or uncommitted migration files, repair dependencies after squashing or renaming apps, and handle third-party app version mismatches.

Problem statement

Every management command fails before it does anything, including runserver, migrate, and check:

django.db.migrations.exceptions.NodeNotFoundError: Migration orders.0015_add_discount
dependencies reference nonexistent parent node ('products', '0009_price_currency')

Django builds a graph of all migration files on disk when it starts. Each migration lists the migrations it depends on. Here, orders/0015 says it needs products/0009, but no file with that name exists in the products app in this checkout. The graph cannot be built, so nothing runs.

Why the graph breaksMigration filelists dependenciesLoader readsall migration filesParent missingnot on diskNodeNotFoundErrornothing runsThe referenced migration file is missing from this environment, not from the database.
  1. Search for the missing file: git log --all --oneline -- products/migrations/0009_price_currency.py.
  2. If it was never committed, commit it from the machine that created it.
  3. If it was deleted or renamed, restore it or update the dependency to the new name.
  4. If the parent belongs to a third-party app, install the package version that contains it.
  5. After squashing, keep the old migrations until every environment has applied the squash.

Step-by-step solution

1. Find out where the file went

ls products/migrations/ | grep 0009
git log --all --oneline -- 'products/migrations/0009*'
git status products/migrations/

Three situations cover almost every case:

  • The file is untracked on a developer's machine and never reached git.
  • The file was deleted, renamed, or squashed away in a later commit.
  • The parent is in an installed package and your environment has a different version.

2. Commit the missing migration

If a teammate ran makemigrations products and committed only the orders migration, the products file exists only on their laptop. Ask them to commit it, or regenerate it carefully: running makemigrations products yourself may produce a file with a different name and contents, which breaks environments that already applied the original. Prefer the original file.

Add a CI check so this cannot reach a deploy again:

python manage.py makemigrations --check --dry-run

It fails when models and migration files disagree, which catches forgotten files early.

where the parent migration wentWhat git showsCause and fixno history for the filenever committed; committhe original filefile deleted in a commitrestore it or repoint the dependencysquashed migration existsold files removed tooearly; restore themparent is a package appversion mismatch; pinthe right releaseThe database is not involved; the file set on disk is incompletedjango-deployment.com
git log on the migrations folder usually identifies the cause in one command.

3. Repair a renamed or deleted parent

If someone renamed 0009_price_currency.py to 0009_currency.py, update every dependency that points at the old name:

grep -rn "0009_price_currency" */migrations/

Change the tuple to ("products", "0009_currency"). If the database already recorded the old name as applied, also update django_migrations so the history matches:

UPDATE django_migrations SET name = '0009_currency'
WHERE app = 'products' AND name = '0009_price_currency';

Do this in every environment, ideally from a data step in your deploy script.

4. Squashed migrations removed too early

After squashmigrations, the squash file has a replaces list. Django can only switch to the squash in an environment once all replaced migrations are applied there. If you deleted the replaced files and another app's migration still depends on one of them, you get this error. Restore the old files, point dependencies at the squash, and remove the originals only after every environment, including developer databases and staging, has migrated past them. See Squash Django Migrations in Production.

5. Third-party app versions

dependencies reference nonexistent parent node ('django_celery_beat', '0019_alter_periodictasks_options')

Your app migration was generated against a newer version of the package than the one installed here. Pin the same version everywhere:

pip show django-celery-beat
pip install "django-celery-beat==2.7.0"

Lock files (uv.lock, poetry.lock, or hashed requirements) prevent different environments from drifting.

keep the migration graph completemakemigrations --check in CIcatches uncommitted filesNever rename applied migrationsadd new ones insteadKeep replaced files after squashuntil all envs migrateLock dependency versionssame package migrationsReview migration diffs in PRsdependencies includedMost incidents trace back to a file that only existed on one laptopdjango-deployment.com
A single CI command removes the most common cause entirely.

Explanation

The migration loader imports every module in each app's migrations package and creates a node per migration and an edge per dependency. A dependency on a node that does not exist is a broken graph, and Django refuses to guess. That is why the error appears even for commands that never touch the database: the graph is built during startup checks. It also explains why the database state does not matter. The fix is always about which files are present.

Edge cases / notes

  • __init__.py missing. If an app's migrations folder lost its __init__.py, Django does not treat it as a package and every migration in it is "missing".
  • .dockerignore patterns. A pattern like **/0*.py meant for something else can drop migration files from the image. Check the image contents.
  • MIGRATION_MODULES. Overriding where an app's migrations live, common in tests, can point dependencies at modules that do not exist in production.

Next steps

FAQ

Can I fix this by faking migrations?

No. Faking writes rows to django_migrations, but this error happens before the database is consulted. The missing file must be restored or the dependency changed.

Why does it work on my laptop?

Your laptop has the file, probably untracked. The server or CI only has what git contains.

Can I just delete the dependency line?

Only if the migration truly does not need that parent. Dependencies usually exist because a foreign key or field refers to the other app's table.

Should I regenerate all migrations from scratch?

Not on a project that has production data. Resetting migrations requires faking initial migrations everywhere and is easy to get wrong.

Keep going