Skip to content

Revision 2 — the current text. The evidence on this page is this revision’s own — it has not been carried forward from, or to, any other revision.

Fixing D1 "no such table" after a migration that seemed to run

Covers the two most common causes: applying a migration to the wrong local/remote target, and a Worker binding pointing at a different database_id than the one that was migrated. Does not cover a migration file that itself has a SQL error (that fails loudly at apply time, not later as "no such table"), or drift specifically caused by an ORM's own migration tracking — see the Drizzle-specific playbook for that. Also covers a preview_database_id on the binding sending wrangler dev to a different database from the one the migration was applied to.

Unverifiedno reproductions yetWhy this confidence?
Revision 2published by DevYou curation

Symptoms

The diagnostic path

10 steps, exactly as this revision published them.

  1. Step 1 · StartD1 query fails with "no such table"

    A SELECT/INSERT/UPDATE against a table fails as if it were never created, despite a migration existing for it.

    What happens next

    • passed step 2, Check which database the migration actually ran against
  2. Step 2 · TestCheck which database the migration actually ran against

    D1 local and remote are separate SQLite databases. wrangler d1 migrations apply needs an explicit --local or --remote flag, and running it once with one flag does not apply it to the other.

    Read-onlysh
    npx wrangler d1 migrations list <DATABASE_NAME> --remote

    Expected result

    The migration you expect is listed under migrations still to be applied, rather than under already-applied ones.

    What happens next

    • passed step 3, Apply the migration to the target that's missing it
    • failed step 4, Check whether the binding points at a different database
    • unknown step 3, Apply the migration to the target that's missing it
  3. Step 3 · FixApply the migration to the target that's missing it

    Run migrations apply against whichever target the failing query is actually hitting — typically --remote for a deployed Worker, --local for wrangler dev.

    Changes statesh

    Changes system or service state. Review before running.

    Applies any pending .sql migration files to the remote D1 database, creating or altering tables as those files specify. It does not delete existing data unless a migration file itself contains a DROP or DELETE statement.

    npx wrangler d1 migrations apply <DATABASE_NAME> --remote

    What happens next

    • passed step 5, Confirm the table exists where you're querying it
  4. Step 4 · TestCheck whether the binding points at a different database

    Confirm the database_id your deployed Worker is actually bound to matches the one you migrated — a stale preview_database_id, or a staging/production database_id mix-up in wrangler.jsonc, will produce exactly this symptom even after a correct migration run.

    Read-onlysh
    npx wrangler d1 info <DATABASE_NAME>

    Expected result

    The database_id shown does not match the database_id in the d1_databases block your Worker is deployed with.

    What happens next

    • passed step 6, Point the binding at the correct database and redeploy
    • failed step 7, Check whether the binding has a preview_database_id
    • unknown step 7, Check whether the binding has a preview_database_id
  5. Step 5 · Verify the fixConfirm the table exists where you're querying it

    List the tables directly against the same target (local/remote) your Worker queries at runtime.

    Read-onlysh
    npx wrangler d1 execute <DATABASE_NAME> --remote --command "SELECT name FROM sqlite_master WHERE type='table';"

    Expected result

    The table you expected appears in the result set.

    What happens next

    • passed step 8, Resolved
    • failed step 9, Not a target/binding mismatch — escalate
    • unknown step 9, Not a target/binding mismatch — escalate
  6. Step 6 · FixPoint the binding at the correct database and redeploy

    Correct the database_id (and preview_database_id if relevant) in your Wrangler configuration to match the database that actually has the migration applied, then redeploy.

    Changes statesh

    Changes system or service state. Review before running.

    Redeploys the Worker so it binds to the D1 database that has the migration applied. No data in either database is modified by this step.

    npx wrangler deploy

    What happens next

    • passed step 5, Confirm the table exists where you're querying it
  7. Step 7 · TestCheck whether the binding has a preview_database_id

    A D1 binding may carry both database_id and preview_database_id. wrangler dev connects to the preview one when it is set, and wrangler d1 migrations apply targets the database you name on the command line — so the two can be different databases while both fields look correct.

    Read-onlysh
    npx wrangler d1 info <PREVIEW_DATABASE_NAME> --remote

    Expected result

    A preview_database_id is present in wrangler.jsonc and names a different database from database_id.

    What happens next

    • passed step 10, Apply the migration to the preview database, or remove the preview binding
    • failed step 9, Not a target/binding mismatch — escalate
    • unknown step 9, Not a target/binding mismatch — escalate
  8. Step 8 · EndResolved

    The correct database has the migration applied and the Worker is bound to that database; the query now succeeds.

  9. Step 9 · EndNot a target/binding mismatch — escalate

    If the migration is applied to the right database and the binding is correct, check whether migrations_table was customised away from the default and the table really was created but under a name or in a way you're not querying — or check the migration file itself for a typo in the table name.

  10. Step 10 · FixApply the migration to the preview database, or remove the preview binding

    Either apply the migration to the preview database as well, or drop preview_database_id so local development uses the same database as deployment. Applying to both is usually right while the schema is still moving; removing it is right once it has settled.

    Changes statesh

    Changes system or service state. Review before running.

    Applies pending migration files to the preview D1 database, creating or altering tables as those files specify.

    npx wrangler d1 migrations apply <PREVIEW_DATABASE_NAME> --remote

    What happens next

    • passed step 5, Confirm the table exists where you're querying it

Sources

Why this confidence?

What would strengthen it: 6 more independent reproductions. Reproductions from 3 more distinct environments.

This counts only what was recorded against revision 2 itself. Nothing reported against another revision is included here — see the revision history for why.