Skip to content

[wrangler] fix: normalize CRLF before sending D1 commands to the remote query API - #15044

Open
stareezy-1 wants to merge 2 commits into
cloudflare:mainfrom
stareezy-1:fix/14991-d1-crlf-migrations
Open

[wrangler] fix: normalize CRLF before sending D1 commands to the remote query API#15044
stareezy-1 wants to merge 2 commits into
cloudflare:mainfrom
stareezy-1:fix/14991-d1-crlf-migrations

Conversation

@stareezy-1

@stareezy-1 stareezy-1 commented Aug 5, 2026

Copy link
Copy Markdown

Fixes #14991

wrangler d1 migrations apply --remote failed with incomplete input: SQLITE_ERROR [7500] whenever a migration file had CRLF line endings and contained a CREATE TRIGGER ... BEGIN ... END; body — the default situation for Windows checkouts with core.autocrlf=true.

Root cause: migrations apply --remote sends the whole migration (plus the tracking INSERT) as one sql string to the D1 /query endpoint, which splits multi-statement SQL on ; server-side and mishandles CRLF inside compound statement bodies. The identical bytes succeed via execute --remote --file because that path uses the D1 import API; the client-side splitter is not involved in the command path (verified against the isolation matrix in the issue: only CRLF + trigger + migrations apply --remote fails).

Fix: normalize CRLF to LF in the remote command path before sending to the query API (input.command.replace(/\r\n/g, "\n")), so the server receives the same input that already works for LF files.


  • Tests
    • Tests included/updated
  • Public documentation
    • Documentation not necessary because: bug fix in an existing command path; no user-facing configuration or API surface changes

Note

This is a contribution from an AI agent: stareezy-1.


Open in Devin Review

The D1 query API splits multi-statement SQL on ';' server-side and
mishandles CRLF line endings inside compound statements such as a CREATE
TRIGGER ... BEGIN ... END; body, producing 'incomplete input: SQLITE_ERROR'.
wrangler d1 migrations apply --remote sends the whole migration (plus the
tracking INSERT) as one command string, so CRLF migrations with triggers
failed while the same bytes via the import-based execute --remote --file
succeeded. Normalize CRLF to LF in the command path before sending.

Closes cloudflare#14991.
@changeset-bot

changeset-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4527e2a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
wrangler Patch
@cloudflare/vite-plugin Patch
@cloudflare/vitest-pool-workers Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@workers-devprod
workers-devprod requested review from a team and emily-shen and removed request for a team August 5, 2026 17:08
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/d1
  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/d1-crlf-remote-query.md: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/d1/execute.test.ts: [@cloudflare/d1 @cloudflare/wrangler]
  • packages/wrangler/src/d1/execute.ts: [@cloudflare/d1 @cloudflare/wrangler]

devin-ai-integration[bot]

This comment was marked as resolved.

- Remove the conventional-commit prefix from the changeset title
  (REVIEW.md forbids type prefixes in changeset titles).
- Re-indent the new execute test to the describe nesting level and apply
  oxfmt so the repository formatting check passes.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

// mishandles CRLF line endings inside compound statements such as a
// `CREATE TRIGGER ... BEGIN ... END;` body (issue #14991). Normalize
// to LF so the server receives the same input that works for LF files.
const sql = input.command?.replace(/\r\n/g, "\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Windows-style line breaks inside quoted text values are silently changed when running against the remote database

Every carriage return in the SQL is stripped out (input.command?.replace(/\r\n/g, "\n") at packages/wrangler/src/d1/execute.ts:510) before the statement is sent, so text values that intentionally contain Windows line breaks are stored differently on the remote database than locally.
Impact: Data inserted or updated through remote commands or migrations loses its carriage returns, producing values that differ from the same command run locally.

Blanket replacement also rewrites string literals, not just statement separators

The replacement is applied to the whole command text, including the inside of quoted SQL string literals. For example wrangler d1 execute db --remote --command "INSERT INTO t(msg) VALUES ('a\r\nb')" (and any migration file with CRLF-containing literals applied via packages/wrangler/src/d1/migrations/apply.ts:158-165) stores a\nb remotely. The local path at packages/wrangler/src/d1/execute.ts:340 does no such normalization, so local and remote execution of identical SQL now diverge. A narrower fix would normalize only outside of quoted literals (e.g. reuse the existing tokenizer in packages/wrangler/src/d1/splitter.ts).

Prompt for agents
The remote query path in packages/wrangler/src/d1/execute.ts normalizes CRLF to LF across the entire command string. This also rewrites the contents of quoted SQL string literals, so text values containing Windows line breaks are silently stored with LF on the remote database, while the local path (same file, around line 340) leaves them untouched — local and remote execution of the same SQL now produce different stored data. Consider normalizing only line endings that are outside of string literals/comments, e.g. by reusing the SQL tokenizer in packages/wrangler/src/d1/splitter.ts, or otherwise limiting the normalization to statement whitespace.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

D1: 'wrangler d1 migrations apply --remote' fails with 'incomplete input: SQLITE_ERROR' on CRLF migration files containing triggers

2 participants