Skip to content

[Windows App] Request to submit deferred migration line-ending checksum fix #38528

Open

Description

@jamespud

Hello,

I have a reviewed and tested fix for the SQL migration CRLF/LF checksum issue tracked in #32643.

Root cause:

SQLx checksums the exact migration bytes embedded at compile time. Migration files checked out with CRLF (for example, on Windows with core.autocrlf=true) therefore produce different checksums than LF checkouts. Databases created by one build fail to open in another with:

migration N was previously applied but has been modified

This also breaks the Windows + WSL shared-Codex-home scenario tracked in #25216 (see #23777, #23841, #23848, #23863), where a WSL runtime must open a database created by a Windows build and vice versa.

Fix:

  • Canonicalizes runtime migrations to LF line endings on all platforms in runtime_migrator(), so embedded checksums no longer depend on checkout line-ending policy.
  • Adds repair_migration_line_ending_checksums(): when opening any runtime SQLite database, _sqlx_migrations rows whose checksum was computed from CRLF migration files are rewritten to the canonical LF checksum, so histories created by either build are accepted interchangeably.
  • Applies to all six runtime migrators (state, logs, goals, memories, queue, thread history).
  • Genuine migration drift is still rejected: the repair only rewrites rows that exactly match the CRLF form of the current migration.

Validation:

  • codex-state: 174/174 tests passed, including 4 new tests (LF invariant across all runtime migrators, CRLF→LF canonicalization, CRLF-applied history accepted after repair, LF-applied history unchanged)
  • scoped Clippy (just fix -p codex-state): clean
  • cargo fmt --check: clean
  • Change is limited to codex-rs/state (+205/-1 across 3 files)

Prepared patch

The fix is available in my fork:

GitHub currently blocks PR creation because only collaborators may open pull requests in this repository.

Could you please either:

  • invite jamespud as a collaborator with permission to open the PR, or
  • open the PR from the prepared fork branch?

Thank you.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    windows-osIssues related to Codex on Windows systems
    on Aug 14, 2026
  2. jdcodes1 commented on Aug 18, 2026

    @jdcodes1

    Independent verification of the root cause against main (1f41cc5): the six runtime DBs all embed their .sql files via sqlx's compile-time migrator (state/src/sqlite.rs, migration dirs like state/migrations/, state/queue_migrations/), and the repo's .gitattributes contains no *.sql text eol=lf rule — only two linguist entries. So on a core.autocrlf=true checkout the embedded bytes really are CRLF, the checksum diverges from LF builds, and migration N was previously applied but has been modified follows exactly as described. The Windows↔WSL shared-home case (#25216) is the worst hit because two differently-built binaries open the same database file.

    One addition to the proposed fix: alongside runtime canonicalization + checksum repair, add *.sql text eol=lf to .gitattributes so future checkouts can't reintroduce the divergence at the source. The repair pass is still needed for databases already stamped with CRLF checksums, and restricting it to rows matching the CRLF form of the current migration keeps genuine-drift detection intact — that design looks right.

  3. jamespud commented on Aug 18, 2026

    @jamespud
    Author

    Independent verification of the root cause against main (1f41cc5): the six runtime DBs all embed their .sql files via sqlx's compile-time migrator (state/src/sqlite.rs, migration dirs like state/migrations/, state/queue_migrations/), and the repo's .gitattributes contains no *.sql text eol=lf rule — only two linguist entries. So on a core.autocrlf=true checkout the embedded bytes really are CRLF, the checksum diverges from LF builds, and migration N was previously applied but has been modified follows exactly as described. The Windows↔WSL shared-home case (#25216) is the worst hit because two differently-built binaries open the same database file.

    One addition to the proposed fix: alongside runtime canonicalization + checksum repair, add *.sql text eol=lf to .gitattributes so future checkouts can't reintroduce the divergence at the source. The repair pass is still needed for databases already stamped with CRLF checksums, and restricting it to rows matching the CRLF form of the current migration keeps genuine-drift detection intact — that design looks right.

    Thanks for the independent verification — glad the root-cause analysis and the checksum-repair design hold up against main.

    I've incorporated your suggestion. The branch now adds a *.sql text eol=lf rule to .gitattributes (commit c291fa484) so every checkout embeds LF regardless of core.autocrlf, closing the source-side gap. For the record, git add --renormalize was a no-op on the existing .sql blobs (they're already stored as LF), so the change stays minimal — the runtime canonicalization + checksum repair in 6247dabb4 remains the part that heals databases already stamped with CRLF checksums.

    Updated branch: jamespud:fix/32643-state-migration-line-endings (commits 6247dabb4 + c291fa484).

  4. changed the title [-]Request to submit deferred migration line-ending checksum fix[/-] [+][Windows App] Request to submit deferred migration line-ending checksum fix[/+] on Aug 21, 2026
  5. Shad0wWulf commented on Aug 30, 2026

    @Shad0wWulf

    I can independently confirm this CRLF/LF migration-checksum problem is still reproducible with a current Windows Desktop + WSL setup, and I was able to recover the existing profile without deleting/rebuilding the affected databases.

    Environment

    • Codex Desktop: 26.825.6671.0
    • Bundled WSL runtime: codex-cli 0.151.0-alpha.7.2
    • Windows + WSL2 Ubuntu
    • WSL kernel: 6.6.87.2-microsoft-standard-WSL2
    • Desktop WSL mode uses the shared Windows Codex home via /mnt/c/Users/<user>/.codex

    Failure

    Running the bundled WSL app-server against the real profile failed with:

    Error: failed to initialize sqlite state runtime under /mnt/c/Users/<user>/.codex: failed to initialize state runtime at /mnt/c/Users/<user>/.codex
    

    This was not ordinary SQLite corruption:

    • PRAGMA quick_check returned ok for the runtime DBs.
    • A clean WSL-native CODEX_HOME worked.
    • A clean CODEX_HOME on /mnt/c also worked, so /mnt/c itself was not sufficient to reproduce the failure.
    • A clone of the real profile with the runtime DBs removed worked.

    Isolation

    Using the same bundled WSL runtime and a 30-second app-server startup test, I tested the existing runtime DBs individually:

    • state_5.sqlite -> FAIL
    • goals_1.sqlite -> FAIL
    • memories_1.sqlite -> FAIL
    • queue_1.sqlite -> FAIL
    • thread_history_1.sqlite -> PASS

    I then generated fresh databases with the exact same WSL runtime and compared _sqlx_migrations.

    The migration versions/descriptions matched, but the checksums differed systematically. For example, state migration 1 in the existing DB began 54 bb d6 f4..., while the fresh WSL DB began 62 7e f1 91..., matching the CRLF/LF checksum pattern described in this issue.

    Controlled proof

    Before touching the real profile, I made a disposable clone containing the original failing goals_1.sqlite.

    1. Original DB -> app-server failed.
    2. I changed only _sqlx_migrations.checksum, copying the checksum values for matching migration versions from a fresh DB generated by the current WSL runtime.
    3. Same DB / same runtime / same test -> app-server passed and remained running for the full 30-second test.

    That provided a useful A/B result: no schema/data rebuild was required; changing only the migration checksum metadata changed FAIL -> PASS.

    Recovery of the real profile

    After making a full backup, I copied the fresh WSL-generated _sqlx_migrations.checksum values into the matching migration rows of:

    • state_5.sqlite
    • goals_1.sqlite
    • memories_1.sqlite
    • queue_1.sqlite

    I left thread_history_1.sqlite untouched because it had already passed independently.

    After that, the original real profile successfully ran the bundled WSL app-server for 30+ seconds. Codex Desktop was then switched back to WSL mode and tested with actual turns: shell commands worked in WSL, files could be created/deleted, and the Desktop Review/diff UI worked normally. Existing profile/history was retained.

    So this appears to be a strong real-world confirmation of the diagnosis and repair strategy in #38528. In particular, the generic failed to initialize sqlite state runtime message can hide a migration checksum incompatibility even when all DBs pass SQLite integrity checks.

    I would strongly recommend an upstream automatic/safe repair along the lines proposed here rather than requiring users to delete/rebuild their state databases.


    This comment was written with assistance from ChatGPT after an interactive diagnostic session; the commands, outputs, A/B tests, and final recovery were run and verified on the affected machine by the user.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingwindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions