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.
Covers SQLITE_BUSY caused by two or more write requests colliding on the same D1 database (including a Worker request racing a Cron Trigger), and by a single invocation issuing many unbatched writes in a row. Does not cover SQLITE_BUSY from an actually-stuck transaction left open by a crashed process, or D1's separate CPU-time/memory-limit resets — those return different, more specific error messages.
Covers the D1-specific per-invocation request cap being hit by an N+1 query pattern or by combining many D1 calls with other subrequests in one invocation. Does not cover the general Workers subrequest limit for fetch()-only Workers with no D1 involved (see Workers platform limits), and does not cover D1's separate CPU-time or memory-limit resets, which return different error text entirely.
Covers genuine duplicate-key inserts and the check-then-insert race that produces the same error under concurrency. Does not cover foreign-key constraint failures (a different SQLITE_CONSTRAINT variant) or CHECK-constraint failures — those need a different diagnosis of the data itself, not of insert timing.
Covers the interactive-confirmation-prompt cause (the most common one, especially in CI or piped/backgrounded shells) and network connectivity to the Cloudflare API as a secondary cause. Does not cover a command that's genuinely still running against a very large file — check for real progress (network/CPU activity) before assuming it's stuck.
Covers schema.ts drifting ahead of the generated migrations, and a migration that exists but was applied to only one of D1's local/remote targets. Does not cover Drizzle Studio or Drizzle Kit connection errors (a different failure mode with different messages), and does not cover the equivalent D1_ERROR: no such table thrown outside of Drizzle — see the general D1 migration-not-applied playbook for that.