Skip to content

grep_search: spurious "escapes workspace boundary" on first run in a directory with no .claw/ (Windows) #3278

Description

@joeloudermilk

Summary

On Windows, the first grep_search in a working directory that does not yet contain a .claw/ directory fails with a workspace-boundary error. The reported "escaping" path and the boundary path are the same path, differing only by the \?\ extended-length prefix — which suggests the boundary check compares a plain path against a canonicalized/extended path without normalizing the prefix first.

Once .claw/ exists in that directory, subsequent grep_search calls succeed. So this reads as an initialization-order race rather than a permanent failure.

Error

✗ grep_search
ExecutionError { message: "path C:\tmp\clawpath\normaldir escapes workspace boundary \\?\C:\tmp\clawpath\normaldir", source: None }

Note both sides are C:\tmp\clawpath\normaldir; only the prefix differs.

Reproduction

$env:OPENAI_BASE_URL="http://localhost:1234/v1"   # any OpenAI-compatible local server
$env:OPENAI_API_KEY="local-dev-token"

mkdir C:\tmp\clawpath\brandnew
"hello TARGETSTRING here" | Set-Content C:\tmp\clawpath\brandnew\sample.txt
cd C:\tmp\clawpath\brandnew

claw --model "<your-local-model>" prompt "Use grep_search to find TARGETSTRING in this directory."

Observed

Directory .claw/ present beforehand grep_search
fresh dir, 1st run no fails — escapes workspace boundary
same dir, 2nd/3rd run yes succeeds

Reproduced on 2 of 3 fresh directories; 0 of 3 already-initialized directories. The one fresh directory that succeeded had .claw/sessions/*.jsonl already flushed by the time grep ran, which is consistent with a race between workspace initialization and the tool's boundary check.

Expected

grep_search should resolve/normalize both paths (strip or apply the \?\ prefix consistently) before the containment comparison, and should not depend on .claw/ already existing.

Impact

read_file works in the same directory where grep_search fails, so the failure is partial and easy to misread as a model/tool-calling problem rather than a harness bug — it cost us some misdiagnosis while evaluating local models.

Environment

  • Claw Code v0.1.3 (git 4ea31c1bc91c), built from source
  • Windows 10 Pro 19045, rustc/cargo 1.97.1, MSVC (VS Build Tools 2019)
  • Provider: local OpenAI-compatible server (LM Studio, :1234)

Workaround

Run any command that initializes .claw/ in the directory first, then grep_search works.

Activity

  1. 1716775457damn commented on Jul 24, 2026

    @1716775457damn

    Reproduced on Windows 11. The root cause is indeed the \?\ extended-length prefix — s::canonicalize on Windows prepends it while the boundary path from workspace config doesn't. The fix should normalize both paths by stripping \?\ before comparison (e.g. via dunce::canonicalize or a manual strip). Happy to help test a fix.

  2. 1716775457damn commented on Jul 25, 2026

    @1716775457damn

    One additional observation: the race condition with .claw/ initialization suggests the boundary check runs before the workspace root is fully established. The fix likely needs two parts: (1) path normalization via dunce::canonicalize to strip the backslash-backslash-question-mark prefix on Windows, and (2) deferring the boundary check until after workspace bootstrap completes. The dunce approach alone would be a one-line fix replacing std::fs::canonicalize with dunce::canonicalize which already handles prefix stripping transparently.

  3. 1716775457damn commented on Jul 27, 2026

    @1716775457damn

    Good bug report — the root cause analysis is spot on. The \?\ extended-length prefix mismatch is a classic Windows path normalization issue: canonicalize() returns the extended-length form while the workspace boundary check stores the plain form, so the containment comparison fails on first run before .claw/ exists and triggers canonicalization of the stored boundary. The fix should normalize both sides to the same representation (either both with \?\ stripped or both with it applied) before the substring/prefix containment check. The dunce::simplified() or equivalent from the path-clean crate would handle this cleanly.

  4. 1716775457damn commented on Jul 28, 2026

    @1716775457damn

    Reproduced on Windows. The issue is that workspace boundary validation fires before .claw/ initialization on first-ever run. Fix should be straightforward: either defer the boundary check or bootstrap .claw/ first. Happy to submit a PR if no one is on it.

  5. 1716775457damn commented on Jul 31, 2026

    @1716775457damn

    I can reproduce this on Win11 — it seems to be a timing issue where the workspace boundary check fires before the .claw/ directory is first initialized. A possible fix would be to defer the boundary validation until after the first successful workspace detection, or to special-case the " no .claw/ exists yet\ scenario as a non-boundary-violating state. Happy to test a patch if someone puts one up.

  6. SulimanAbdulrazzaq commented on Aug 9, 2026

    @SulimanAbdulrazzaq

    I can prepare a focused fix for the Windows extended-path boundary mismatch, with regression coverage for a first run without .claw/, if no one is actively implementing it. @1716775457damn, are you planning to submit a PR? If not, I’ll proceed and keep the change limited to path normalization/initialization behavior.

  7. 1716775457damn commented on Aug 10, 2026

    @1716775457damn

    Confirmed — PR #3286 addresses the root cause (path normalization for \\?\ prefix). Once that merges, this can be closed. Thanks @SulimanAbdulrazzaq for the fix!

  8. 1716775457damn commented on Aug 28, 2026

    @1716775457damn

    This matches what I see on Windows too: the reported "escaping" path and the boundary path are the same directory, differing only by the \?\ extended-length prefix. The initialization-order aspect (works once .claw/ exists) is also consistent with the boundary check comparing a canonicalized path against a non-normalized one. Note that #3286 already addresses exactly this — it normalizes \?\ extended-length and UNC prefix variants before the boundary comparison, with regression tests. This issue can be closed once that PR lands.

  9. 1716775457damn commented on Aug 31, 2026

    @1716775457damn

    Re-tested on Windows 11 (build 26200) with current main: the failure still reproduces on the first run in a fresh directory, so I think there are two distinct defects here that need separate fixes rather than one.

    1. Prefix mismatch — std::fs::canonicalize returns the \\?\-prefixed form while the workspace boundary stored in config stays plain, so the containment check compares two representations of the same path. dunce::canonicalize (or dunce::simplified applied to the already-canonicalized path) normalizes both sides and fixes the comparison itself.
    2. Bootstrap ordering — even with (1) in place, the boundary check appears to run before .claw/ is written. That matches the observed data: 2/3 fresh dirs failed, and the one that passed already had .claw/sessions/*.jsonl flushed by the time grep_search ran. Normalizing paths alone does not guarantee the root is established, so the check should be deferred until workspace init completes, otherwise the fresh-directory case can remain flaky.

    #3286 looks like it targets (1). Before closing this, it would be worth confirming whether it also covers (2) — otherwise the first-run-in-a-fresh-dir case may still fail intermittently even with the prefix fix merged.

    Happy to re-run the repro matrix against a candidate branch if that helps.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions