knex migration error: migration file not found for the latest batch
How to fix knex's "migration file not found for the latest batch": reconciling the knex_migrations table with the files on disk by restoring the deleted file or removing the orphaned row. Use when migrate commands fail because the latest batch references a file that no longer exists. Not for migrations that fail while running.
TL;DR
The knex_migrations table says the latest batch ran a file that is not on disk, usually deleted or lost in a branch switch. Find the orphaned row, restore the file from version control when the migration is real, or delete the row when the migration never actually ran. Then run knex migrate:list to prove the table and the directory agree.
The query
knex migration error: migration file not found for the latest batchUse this when
- knex fails with "migration file not found for the latest batch"
- A migration file was deleted after it ran
- knex_migrations references a file missing from the migrations directory
- An agent cleaned up files and broke the history
Not for
- A migration that errors while running (fix the migration code)
- knex_migrations table missing entirely (the database was never migrated)
- Seed files failing (seeds are tracked separately, if at all)
Steps
1. Find the orphaned row
SELECT id, name, batch, migration_time FROM knex_migrations ORDER BY id DESC LIMIT 5;Compare the latest batch's names against the files in the migrations directory.
Expected output: the row whose file is missing, e.g. the latest batch names 20241011addindex.js but no such file exists.
2. Check version control for the deleted file
git log --diff-filter=D --name-only -- [migrations dir]/ | head -20Expected output: the deleted filename and the commit that removed it. If git has it, restoration is the safe path.
3. Case A: the migration is real - restore the file
git checkout [commit before deletion] -- [migrations dir]/[file].jsExpected output: the file is back and knex migrate:list no longer complains. The restored file must match what ran; knex does not checksum, but future developers read this file as history.
4. Case B: the migration never actually ran - remove the row
DELETE FROM knex_migrations WHERE name = '[orphaned name]';Only when you are certain the migration's effects are absent from the database (its tables or columns do not exist). Expected output: the orphaned row is gone and the latest batch once again resolves to files on disk.
5. Verify agreement between table and directory
npx knex migrate:listExpected output: completed and pending migrations list cleanly with no "file not found". On a fresh database, run migrate:latest from zero to prove new environments bootstrap.
Tool compatibility
knex 2.x and 3.x with any supported database. knex_migrations bookkeeping is the same across versions.
Variant phrasings
knex migration file not found for the latest batch
Steps 1 through 3: find the orphaned row, restore the file from git.
knex_migrations references deleted file
Step 4 only when the migration truly never ran: delete the row, and verify its effects are absent first.
knex migrate:list file not found
Step 5: migrate:list is the check that table and directory agree. Run it after every fix.
Why it happens
Knex records each applied migration by filename in knex_migrations but never verifies the file still exists until it needs to list or roll back. Deleting a file orphans its history row, and the next command that walks the batch fails on the missing file. Knex has no checksums, so restoration is purely about keeping history readable.
Edge cases
- Because knex does not checksum, a restored file with different content silently rewrites history: restore from the commit that was current when it ran.
- If the orphaned batch is mid-list (not the latest), the same procedure applies row by row; fix the latest first since that is what commands walk.
- Rollback of a batch with a missing file is impossible: restore the file before attempting knex migrate:rollback.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_IkEA2neVmn8hskIo01C6cA