## 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

```text
knex migration error: migration file not found for the latest batch
```

## Use 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

```sql
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 20241011_add_index.js but no such file exists.

### 2. Check version control for the deleted file

```bash
git log --diff-filter=D --name-only -- [migrations dir]/ | head -20
```

Expected 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

```bash
git checkout [commit before deletion] -- [migrations dir]/[file].js
```

Expected 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

```sql
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

```bash
npx knex migrate:list
```

Expected 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
