cloudflare / cloudflare/workers-sdk
wrangler d1 migrations apply --local fails with SQLITE_LOCKED while remote D1 succeeds
- Dominant language
- TypeScript
- Stars
- 4.5k
- Forks
- 1.5k
- Avg merge
- 3d 8h
- Merged PRs (30d)
- 186
Description
### What versions & operating system are you using?
```text
System:
OS: macOS 26.6.1
CPU: (8) arm64 Apple M1
Memory: 1.97 GB / 8.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 26.1.0
npm: 11.17.0
pnpm: 11.7.0
bun: 1.3.14
Deno: 2.9.2
npmPackages:
wrangler: 4.122.0
```
The local failure also reproduces on Wrangler 4.112.0 and 4.121.0.
### Please provide a link to a minimal reproduction
https://github.com/atiqrahmanx/wrangler-d1-local-sqlite-locked-repro
### Describe the Bug
`wrangler d1 migrations apply --local` deterministically fails with
`database table is locked: SQLITE_LOCKED` on a clean local database, while the
same migration files apply successfully to a fresh remote D1 database.
Steps to reproduce:
```sh
git clone https://github.com/atiqrahmanx/wrangler-d1-local-sqlite-locked-repro.git
cd wrangler-d1-local-sqlite-locked-repro
pnpm install
pnpm repro
```
The config uses a dummy all-zero database UUID and a nested Drizzle-style
`migrations/*/migration.sql` layout via `migrations_pattern`.
On a clean local persistence directory, Wrangler applies and records the first
four migrations, then fails on
`20260810185351_marvelous_korvac/migration.sql`. Repeating the command leaves
the first four recorded and fails on that fifth migration again.
For comparison, I created a brand-new remote D1 database in APAC and ran the
same five files through `wrangler d1 migrations apply --remote` using Wrangler
4.121.0. All five succeeded without modification. The final migration executed
194 commands remotely. The resulting remote schema had all 203 tables/indexes
declared by the latest Drizzle snapshot and no `PRAGMA foreign_key_check`
violations.
Expected behavior: local D1 should either apply SQL that remote D1 accepts or
report a specific documented local incompatibility. A deterministic table lock
on a single-process clean migration makes local migration validation report a
false deployment failure.
This may share local-D1 locking internals with #14916, but it is not the same
failure mode: #14916 concerns concurrent writes causing `SQLITE_BUSY` and
crashing `wrangler dev`; this reproduction is serial, uses
`d1 migrations apply --local`, and fails deterministically with
`SQLITE_LOCKED`.
### Please provide any relevant error logs
```text
⛅️ wrangler 4.122.0
Resource location: local
20260722013352_stale_pestilence/migration.sql ✅ 211 commands
20260722024523_white_malice/migration.sql ✅ 4 commands
20260726183531_safe_hellfire_club/migration.sql ✅ 11 commands
20260801213046_narrow_black_tarantula/migration.sql ✅ 49 commands
20260810185351_marvelous_korvac/migration.sql pending
✘ [ERROR] database table is locked: SQLITE_LOCKED
```
Remote comparison:
```text
⛅️ wrangler 4.121.0
Resource location: remote
20260722013352_stale_pestilence/migration.sql ✅ 211 commands
20260722024523_white_malice/migration.sql ✅ 4 commands
20260726183531_safe_hellfire_club/migration.sql ✅ 11 commands
20260801213046_narrow_black_tarantula/migration.sql ✅ 199 commands
20260810185351_marvelous_korvac/migration.sql ✅ 194 commands
```
Contributor guide
Research direction
Clone the linked reproduction, run pnpm install and pnpm repro, and inspect the migrations/*/migration.sql files, especially 20260810185351_marvelous_korvac/migration.sql. Start by tracing the local path used by wrangler d1 migrations apply --local and compare it with the successful remote path. Done means the clean local database applies all five migrations without SQLITE_LOCKED and records the final migration.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- sqlite, typescript
- Domain
- cli, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100