Skip to content

core: instruction discovery stack-overflows with case-variant Windows paths ("Instruction initialization blocked: core/instructions") #52874

Closed

Description

@codemonkey1101

Description

On Windows, a TUI client launched from a terminal whose CWD drive letter has non-canonical casing (e.g. c:\repo instead of C:\repo) registers a second location in the shared service whose instruction-source activation stack-overflows:

level=WARN message="failed to activate instruction source" cause="Cause([Die(RangeError: Maximum call stack size exceeded.)])"

Instruction discovery for that location is then permanently unavailable, and every prompt in it fails with:

Instructions.InitializationBlocked: Instruction initialization blocked by unavailable sources: core/instructions
    at InstructionState.observe / InstructionState.prepare / SessionRunner.prepareContext / SessionRunner.drain

Root cause — ancestorDirectories in packages/core/src/config/plugin/instruction.ts (identical in v2.0.21 and v2.0.22):

function ancestorDirectories(start: string, stop: string): string[] {
  if (start === stop) return [start]
  return [start, ...ancestorDirectories(dirname(start), stop)]
}
  • start comes from fs.resolve(location.directory) — the client's raw CWD. Bun's fs.realPath does not case-canonicalize on Windows, so a lowercase c:\ form survives resolution (confirmed in the logs: same-run git spawns show cwd="C:\repo" and cwd="c:\repo").
  • stop comes from fs.resolve(location.project.directory), derived from git rev-parse --show-toplevel, which canonicalizes to C:\repo.
  • When the two differ only in casing, start === stop never matches: the walk recurses upward, reaches the drive root where dirname("c:\") === "c:\", and self-recurses until the stack overflows. The sibling walker FileSystem.up (packages/util/src/fs-util.ts) has a root guard (if (parent === current) break) — ancestorDirectories lacks it.
  • Downstream: the dead activation marks the instruction-discovery state unavailable(), InstructionDiscovery.list returns the Unavailable signal, and every session drain in that location throws InitializationBlocked.

Suggested fix

  1. Add the same root guard fs.up has (if (dirname(start) === start) return [start]), so the walk terminates regardless.
  2. Compare case-insensitively on win32 (or canonicalize both sides through a case-resolving path API — path.resolve alone is insufficient since Bun's realPath preserves drive-letter casing on Windows).

Workaround (verified): launch clients with canonically-cased CWDs (e.g. a wrapper that rewrites a leading c:\ to C:\ before exec), then restart the service to clear the poisoned location.

Plugins

One project-local plugin (unrelated — failure is in core location/instruction initialization, reproducible with the second client alone).

OpenCode version

v2.0.21 (verified the cited code is unchanged in v2.0.22)

Steps to reproduce

  1. On Windows, launch a first TUI from a canonically-cased CWD (C:\repo). Prompts work normally.
  2. Launch a second TUI from a terminal whose process CWD is the same directory with a lowercase drive letter (c:\repo — e.g. Git Bash resolves /c/repo this way).
  3. In the second TUI, send any prompt — the drain fails with InitializationBlocked: core/instructions. The overflow recurs each time the lowercase location boots (42 occurrences in one day of logs on this machine).

Screenshot and/or share link

No response

Operating System

Windows 11 (10.0.26200), x64

Terminal

Windows Terminal

Activity

  1. github-actions commented on Oct 2, 2026

    @github-actions
    Contributor

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

    • #50750: Stack overflow activating instruction discovery for case-variant Windows paths.
    • #50857: Lowercase Windows drive letter causes instruction activation stack overflow and blocks sessions.
    • #47839: Case-sensitive duplicate Windows locations break instruction initialization.
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