cloudflare / cloudflare/workers-sdk

wrangler d1 migrations apply --local fails with SQLITE_LOCKED while remote D1 succeeds

Open
#15,162 2 comments 0 reactions 0 assignees View on GitHub
package:miniflare product:d1
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.