Skip to content

instructions: Windows lowercase drive letter in workspace path causes stack overflow, blocking all sessions #50857

Closed

Description

@zjsygqs398

Summary

On Windows, launching opencode from a directory whose drive letter is lowercase (e.g. d:\workspace\repo) makes the built-in instruction source core/instructions fail activation with RangeError: Maximum call stack size exceeded. Every session in that location then fails with:

Session failed
Instruction initialization blocked by unavailable sources: core/instructions

Launching the exact same workspace with an uppercase drive letter (D:\workspace\repo) works fine. cmd.exe preserves the drive-letter case the user types, so whether a workspace works depends purely on how you cd into it.

Environment

  • opencode version: v2.0.14 (also observed on 2.0.12 running as opencode serve --service)
  • OS: Windows 10 22H2 (10.0.19045), win32 x64
  • Terminal: Windows console
  • Shell: cmd.exe
  • Install/channel: npm global @opencode/cli 2.0.14, latest channel
  • Active plugins: none configured

Reproduction

  1. Open cmd.exe
  2. cd /d d:\workspace\some-git-repo - note the lowercase drive letter (cmd preserves typed case)
  3. Run opencode
  4. Create a new session

Repeating the exact same steps with cd /d D:\workspace\some-git-repo (uppercase D) works every time.

This is 100% deterministic in my logs: every location boot with a lowercase drive letter failed instruction activation; every boot of the same workspace with an uppercase drive letter succeeded.

Expected Behavior

Drive-letter case should not matter on Windows. Sessions should start normally regardless of the case of the workspace path.

Actual Behavior

Instruction source activation dies with a stack overflow, and every new session in that location fails with Instructions.InitializationBlocked: Instruction initialization blocked by unavailable sources: core/instructions.

Additional Context

Root cause analysis (log correlation + binary inspection of 2.0.14)

The instruction source activation (ConfigInstructionPlugin) computes:

p = resolve(location.directory)        // preserves typed case -> "d:\workspace\repo"
g = resolve(project.directory)         // from `git rev-parse --show-toplevel`, which always
                                       // returns an UPPERCASE drive on Windows ("D:/workspace/repo")
f = contains(home, p) ? home : g       // workspace not under HOME -> f = g = "D:\workspace\repo"
sources = [...global, ...chain(p, f)]  // chain() walks p upward via dirname() until it === f

The chain walk terminates on strict equality e === a. Because p is d:\... and f is D:\..., equality never holds. At the drive root, dirname("d:\") === "d:\" is a fixed point, so the recursion never terminates -> stack overflow.

The guard that admits execution into this branch, contains(g, p), is case-insensitive (path.relative-based), which is why the mismatched-case walk is reached at all:

path.win32.resolve('d:\\workspace\\repo')                         // 'd:\\workspace\\repo'  (case preserved)
path.win32.resolve('D:/workspace\\repo')                          // 'D:\\workspace\\repo'
path.win32.dirname('d:\\')                                        // 'd:\\'                 (fixed point!)
path.win32.relative('D:\\workspace\\repo', 'd:\\workspace\\repo') // ''                     (case-insensitive)

Log evidence

# lowercase drive letter -> failure (~270ms after location boot)
message="location services booted" directory="d:\\workspace\\lab-emc\\lab-emc"
message="failed to activate instruction source" cause="Cause([Die(RangeError: Maximum call stack size exceeded.)])"
message="Failed to drain Session" cause="Instructions.InitializationBlocked: Instruction initialization blocked by unavailable sources: core/instructions"

# same workspace, uppercase drive letter -> success
message="location services booted" directory="D:\\workspace\\lab-emc\\lab-emc"
message="watcher subscribe" path="C:\\Users\\<user>\\.config\\opencode\\AGENTS.md" type=file
message="watcher subscribe" path="D:\\workspace\\lab-emc\\lab-emc\\AGENTS.md" type=file

The activation error handler marks the source unavailable for the process lifetime ("failed to activate instruction source", WARN); each subsequent session then throws Instructions.InitializationBlocked ("Failed to drain Session", ERROR).

Suggested fix

  • Terminate the chain walk when dirname(e) === e (root fixed point), and/or
  • Compare the walk target case-insensitively on win32 (consistent with the contains guard).

Workaround

Always launch with an uppercase drive letter: cd /d D:\workspace\repo before opencode.

Activity

  1. github-actions commented on Sep 23, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  2. drhanfastolfe commented on Sep 24, 2026

    @drhanfastolfe

    Confirmed on OpenCode v2.0.16 on Windows.

    Using the same server, agent, model, and prompt:

    • c:\repos\local\my-project fails with Instruction initialization blocked by unavailable sources: core/instructions.
    • C:\repos\local\my-project works.

    Changing only the drive letter to uppercase consistently fixes it. I did not encounter this problem in v1.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions