Skip to content

fix: normalize filepath in FileTime to prevent Windows path mismatch#20367

Merged
Hona merged 2 commits into
anomalyco:devfrom
JosXa:fix-filetime-path-normalization
Apr 1, 2026
Merged

fix: normalize filepath in FileTime to prevent Windows path mismatch#20367
Hona merged 2 commits into
anomalyco:devfrom
JosXa:fix-filetime-path-normalization

Conversation

@JosXa
Copy link
Copy Markdown
Contributor

@JosXa JosXa commented Mar 31, 2026

Issue for this PR

Closes #20354

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

On Windows, the Read tool normalizes file paths (forward slashes to backslashes, canonical casing via realpathSync.native) before calling FileTime.read(), which stores the normalized path as a Map key. But Write and Edit tools pass the raw path (often with forward slashes from LLM output) to FileTime.assert(), which looks up the un-normalized key and fails with a false "must read file before editing/writing" error.

The fix adds Filesystem.normalizePath() at the entry of all four FileTime Effect functions (read, get, assert, getLock). This is the single choke point where all file-time operations converge, so normalizing here guarantees consistent Map keys regardless of how callers format the path. On non-Windows platforms, normalizePath is a no-op, so there's no behavioral change.

How did you verify your code works?

  1. Typecheck passes
  2. All 19 FileTime tests pass (15 existing + 4 new path normalization tests covering forward/backslash combinations for read, get, assert, and withLock)
  3. Ran the patched build via bun dev run with the exact repro steps from the issue (Read with forward slashes then Edit/Write with same forward-slash path) - both succeeded without error

Screenshots / recordings

N/A - no UI change

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions github-actions Bot added contributor needs:compliance This means the issue will auto-close after 2 hours. labels Mar 31, 2026
@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search results, I found two related PRs about Windows path normalization that might be relevant:

These PRs appear to address similar Windows path normalization issues, though they focus on session queries rather than FileTime specifically. However, they're addressing the same underlying problem of path format inconsistencies on Windows. You may want to verify if there's any overlap in scope or if these should be coordinated.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Mar 31, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@Hona Hona merged commit 880c0a7 into anomalyco:dev Apr 1, 2026
5 of 8 checks passed
@Hona
Copy link
Copy Markdown
Member

Hona commented Apr 1, 2026

thanks mate - good catch.

I've been using the hashline edits so I don't really see it

katosun2 pushed a commit to katosun2/opencode that referenced this pull request Apr 2, 2026
jeromelau pushed a commit to jeromelau/opencode that referenced this pull request Apr 2, 2026
NicholasDominici added a commit to jairad26/opencode that referenced this pull request Apr 6, 2026
* refactor(init): tighten AGENTS guidance (anomalyco#20422)

* refactor(shell): use Effect ChildProcess for shell command execution (anomalyco#20494)

* refactor: use Effect services instead of async facades in provider, auth, and file (anomalyco#20480)

* chore: generate

* chore: update nix node_modules hashes

* Update VOUCHED list

anomalyco#20482 (comment)

* test(app): migrate more e2e suites to isolated backend (anomalyco#20505)

* fix(account): coalesce concurrent console token refreshes (anomalyco#20503)

* test(app): fix isolated backend follow-ups (anomalyco#20513)

* wip: zen

* refactor: replace BunProc with Npm module using @npmcli/arborist (anomalyco#18308)

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Brendan Allan <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* zen: sync

* fix: normalize filepath in FileTime to prevent Windows path mismatch (anomalyco#20367)

Co-authored-by: JosXa <[email protected]>
Co-authored-by: Luke Parker <[email protected]>

* resolve subpath only packages for plugins (anomalyco#20555)

* Fix selection expansion by retaining focused input selections during global key events (anomalyco#20205)

* feat: add new provider plugin hook for resolving models and sync models from github models endpoint (falls back to models.dev) (anomalyco#20533)

* fix(tui): apply scroll configuration uniformly across all scrollboxes (anomalyco#14735)

* chore(tui): clean up scroll config follow-up (anomalyco#20561)

* fix(opencode): batch snapshot revert without reordering (anomalyco#20564)

* fix(test): auto-acknowledge tool-result follow-ups in mock LLM server (anomalyco#20528)

* chore: generate

* refactor: add Effect-returning versions of MessageV2 functions (anomalyco#20374)

* refactor(bash): use Effect ChildProcess for bash tool execution (anomalyco#20496)

* chore: generate

* Refactor plugin/config loading, add theme-only plugin package support (anomalyco#20556)

* fix(test): use effect helper in snapshot race test (anomalyco#20567)

* refactor(revert): yield SessionSummary.Service directly (anomalyco#20541)

* fix: show model display name in message footer and transcript (anomalyco#20539)

* flock npm.add (anomalyco#20557)

* fix(account): refresh console tokens before expiry (anomalyco#20558)

* chore: add User-Agent headers for Cloudflare providers (anomalyco#20538)

Co-authored-by: Aiden Cline <[email protected]>

* fix(build): replace require() with dynamic import() in cross-spawn-spawner (anomalyco#20580)

* chore: generate

* tui: add consent dialog when sharing for the first time (anomalyco#20525)

* test(app): block real llm calls in e2e prompts (anomalyco#20579)

* refactor(instruction): migrate to Effect service pattern (anomalyco#20542)

* fix(cli): use simple logo in CLI (anomalyco#20585)

* fix(core): prevent agent loop from stopping after tool calls with OpenAI-compatible providers (anomalyco#14973)

Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* fix(session): compaction agent responds in same language as conversation (anomalyco#20581)

Co-authored-by: Aaron Zhu <[email protected]>

* refactor(account): share token freshness helper (anomalyco#20591)

* fix(cli): restore colored help logo (anomalyco#20592)

* feat(opencode): Add Venice AI package as dependency (anomalyco#20570)

* chore: generate

* cli: update usage exceeded error

* chore: update nix node_modules hashes

* fix(node): set OPENCODE_CHANNEL during build (anomalyco#20616)

* zen: friendly trial ended message

* refactor: simplify solid reactivity across app and web (anomalyco#20497)

* use solid-primitives/resize-observer across web code (anomalyco#20613)

* cleanup event listeners with solid-primitives/event-listener (anomalyco#20619)

* chore: update nix node_modules hashes

* refactor: split up models.dev and config model definitions to prevent coupling (anomalyco#20605)

* chore: generate

* feat: add optional messageID to ShellInput (anomalyco#20657)

* chore: generate

* ignore: fix typecheck in dev (anomalyco#20702)

* fix(format): use biome format instead of check to prevent import removal (anomalyco#20545)

Co-authored-by: Aiden Cline <[email protected]>

* tweak: add abort signal timeout to the github copilot model fetch to prevent infinite blocking (anomalyco#20705)

* Add MiMo-V2 models to Go UI and docs (anomalyco#20709)

* refactor(format): update formatter interface to return command from enabled() (anomalyco#20703)

* app: unify auto scroll ref handling (anomalyco#20716)

* go: add mimo

* electron: add basic context menu for inspect element (anomalyco#20723)

* feat: add macOS managed preferences support for enterprise MDM deployments (anomalyco#19178)

Co-authored-by: Lenny Vaknine <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* chore: generate

* feat(acp): Add messageID and emit user_message_chunk on prompt/command (anomalyco#18625)

Co-authored-by: Aiden Cline <[email protected]>

* chore: generate

* test(app): add a golden path for mocked e2e prompts (anomalyco#20593)

* chore: update nix node_modules hashes

* docs(effect): refresh migration status (anomalyco#20665)

* test(opencode): remove temporary e2e url repro (anomalyco#20729)

* refactor(app): unexport internal e2e helpers (anomalyco#20730)

* test(app): emit junit artifacts for playwright (anomalyco#20732)

* refactor(todo): effectify session todo (anomalyco#20595)

* Adds TUI prompt traits, refs, and plugin slots (anomalyco#20741)

* chore: update nix node_modules hashes

* dialog aware prompt cursor (anomalyco#20753)

* fix(opencode): honor model limit.input overrides (anomalyco#16306)

Co-authored-by: Aiden Cline <[email protected]>

* refactor(effect): prune unused facades (anomalyco#20748)

* fix: rm dynamic part from bash tool description again to restore cache hits across projects (anomalyco#20771)

* refactor(share): effectify share next (anomalyco#20596)

* fix: call models.dev once instead of twice on start (anomalyco#20765)

* fix: prevent Tool.define() wrapper accumulation on object-defined tools (anomalyco#16952)

Co-authored-by: Claude Opus 4.6 <[email protected]>

* chore: generate

* add automatic heap snapshots for high-memory cli processes (anomalyco#20788)

* feat: Send x-session-affinity and x-parent-session-id headers (anomalyco#20744)

* fix(sdk): handle Windows opencode spawn and shutdown (anomalyco#20772)

* chore: update nix node_modules hashes

* electron: better menus (anomalyco#20878)

* fix(core): fix restoring earlier messages in a reverted chain (anomalyco#20780)

* fix(session): delay jump-to-bottom button (anomalyco#20853)

* fix(prompt): unmount model controls in shell mode (anomalyco#20886)

* fix(session): disable todo dock auto-scroll (anomalyco#20840)

* feat(ui): redesign modified files section in session turn (anomalyco#20348)

Co-authored-by: David Hill <[email protected]>

* fix(app): hide default session timestamps (anomalyco#20892)

* refactor(effect): resolve built tools through the registry (anomalyco#20787)

* fix: restore prompt focus after footer selection (anomalyco#20841)

* feat: restore git-backed review modes (anomalyco#20845)

* chore: generate

* fix(app): show correct submit icon when typing follow up

* chore(app): remove queued follow-ups for now

* refactor(effect): build todowrite tool from Todo service (anomalyco#20789)

Co-authored-by: Juan Pablo Carranza Hurtado <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>

* test(ci): publish unit reports in actions (anomalyco#20547)

* chore: rm models snapshot (anomalyco#20929)

* notes on v2 (anomalyco#20941)

* chore: generate

* refactor(provider): stop custom loaders using facades (anomalyco#20776)

Co-authored-by: luanweslley77 <[email protected]>

* perf(opencode): batch snapshot diffFull blob reads (anomalyco#20752)

Co-authored-by: Nate Williams <[email protected]>

* fix(ci): create JUnit output dirs before tests (anomalyco#20959)

* release: v1.3.14

* refactor: remove redundant Kimi skill section (anomalyco#20393)

Co-authored-by: dongyuxin <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* fix(npm): Arborist reify fails on compiled binary — Bun pre-resolves node-gyp path at build time (anomalyco#21040)

* release: v1.3.15

* fix: ensure reasoning tokens arent double counted when calculating usage (anomalyco#21047)

* feat(tui): show console-managed providers (anomalyco#20956)

* refactor(effect): move read tool onto defineEffect (anomalyco#21016)

* chore: generate

* fix(tui): only show org switch affordances when useful (anomalyco#21054)

* chore: generate

* test: add regression test for double counting bug (anomalyco#21053)

* doc: udpate doc

* tweak: add newline between <content> and first line of read tool output to prevent confusion (anomalyco#21070)

* fix(plugin): parse package specifiers with npm-package-arg and sanitize win32 cache paths (anomalyco#21135)

* chore: update nix node_modules hashes

* feat(tui): make the mouse disablable (anomalyco#6824, anomalyco#7926) (anomalyco#13748)

* fix(core): implement proper configOptions for acp (anomalyco#21134)

* fix: pass both 'openai' and 'azure' providerOptions keys for @ai-sdk/azure (anomalyco#20272)

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* fix(tui): default Ctrl+Z to undo on Windows (anomalyco#21138)

* release: v1.3.16

* zen: remove header check

* zen: normalize ipv6

* fix: show clear error when Cloudflare provider env vars are missing (anomalyco#20399)

Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* fix(tui): revert kitty keyboard events workaround on windows (anomalyco#20180)

* release: v1.3.17

* fix(lsp): MEMORY LEAK: ensure typescript server uses native project config (anomalyco#19953)

* chore: generate

* docs: update Cloudflare provider setup to reflect /connect prompt flow (anomalyco#20589)

* refactor: replace Bun.serve with Node http.createServer in OAuth handlers (anomalyco#18327)

Co-authored-by: LukeParkerDev <[email protected]>

* upgrade opentui to 0.1.97 (anomalyco#21137)

* refactor(server): replace Bun serve with Hono node adapters (anomalyco#18335)

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Luke Parker <[email protected]>
Co-authored-by: Adam <[email protected]>
Co-authored-by: Brendan Allan <[email protected]>

* chore: update nix node_modules hashes

* tweak: ensure copilot anthropic models have same reasoning effort model as copilot cli, also fix qwen incorrectly having variants (anomalyco#21212)

* tweak: adjust chat.params hook to allow altering of the maxOutputTokens (anomalyco#21220)

* tweak: move the max token exclusions to plugins  @rekram1-node (anomalyco#21225)

* fix: bump openrouter ai sdk pkg to fix openrouter issues (anomalyco#21242)

---------

Co-authored-by: Shoubhit Dash <[email protected]>
Co-authored-by: Kit Langton <[email protected]>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank <[email protected]>
Co-authored-by: Dax <[email protected]>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Brendan Allan <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: Joscha Götzer <[email protected]>
Co-authored-by: JosXa <[email protected]>
Co-authored-by: Luke Parker <[email protected]>
Co-authored-by: Sebastian <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: MC <[email protected]>
Co-authored-by: Valentin Vivaldi <[email protected]>
Co-authored-by: Aaron Zhu <[email protected]>
Co-authored-by: Aaron Zhu <[email protected]>
Co-authored-by: dpuyosa <[email protected]>
Co-authored-by: Brendan Allan <[email protected]>
Co-authored-by: Noam Bressler <[email protected]>
Co-authored-by: Burak Yigit Kaya <[email protected]>
Co-authored-by: Jack <[email protected]>
Co-authored-by: Lenny Vaknine <[email protected]>
Co-authored-by: Lenny Vaknine <[email protected]>
Co-authored-by: ykswang <[email protected]>
Co-authored-by: Juan Pablo Carranza Hurtado <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Kevin Flansburg <[email protected]>
Co-authored-by: Nate Williams <[email protected]>
Co-authored-by: David Hill <[email protected]>
Co-authored-by: Adam <[email protected]>
Co-authored-by: luanweslley77 <[email protected]>
Co-authored-by: opencode <[email protected]>
Co-authored-by: Yuxin Dong <[email protected]>
Co-authored-by: dongyuxin <[email protected]>
Co-authored-by: Gautier DI FOLCO <[email protected]>
Co-authored-by: George Harker <[email protected]>
Co-authored-by: Corné Steenhuis <[email protected]>
Co-authored-by: Derek Barrera <[email protected]>
balcsida pushed a commit to balcsida/opencode that referenced this pull request Apr 8, 2026
xywsxp pushed a commit to xywsxp/opencode that referenced this pull request Apr 24, 2026
Rwanbt pushed a commit to Rwanbt/opencode that referenced this pull request May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: FileTime read-gate path normalization mismatch causes false 'must read first' errors

2 participants