Skip to content

Windows: Rel: can't make <file> relative to <base> on every Write/Edit when the project is on a different drive from the plugin #60

Description

@namlh-mx

Summary

On Windows, when the project lives on a different drive letter than the base the hook relativizes against, every Write/Edit injects this into the model's context as additionalContext:

Rel: can't make D:\Projects\App\src\Foo.cs relative to C:\Users\me\.claude\plugins\cache\claude-plugins-official\semgrep\2.1.2

Go's filepath.Rel returns an error for paths on different Windows volumes (golang/go#13259) — there is no relative path between C:\… and D:\…. Plugins are always installed under ~/.claude on C:, so any project on D: (or any other drive) hits this on every single file write.

This looks like a regression from the fix for #49 / #50: the old bug was filepath.Join($PWD, absolutePath); the fix appears to have moved to relativizing against a base, which introduced a cross-volume failure the previous code did not have.

Environment

  • Plugin: semgrep@claude-plugins-official v2.1.2 (latest; hook-windows-amd64.exe)
  • Claude Code 2.1.211
  • Windows 11 26200.8875, x86_64, Git Bash (OSTYPE=msys, bash 5.2.37) — not WSL
  • Project on D:, plugin cache + ~/.semgrep on C:

Reproduction

With Claude Code open on a project on D:, any Write or Edit produces the error above as additionalContext. It also reproduces by piping a payload straight into the binary — and note the base is not the payload's cwd field, it tracks the process $PWD (consistent with the observation in #49 that the binary ignores stdin cwd):

cd /d/Projects/App
python - <<'PY'
import json
BS = chr(92)
p = {"session_id":"probe","transcript_path":"C:"+BS+"temp"+BS+"t.jsonl",
     "cwd":"D:"+BS+"Projects"+BS+"App",
     "hook_event_name":"PostToolUse","tool_name":"Write",
     "tool_input":{"file_path":"C:"+BS+"Users"+BS+"me"+BS+"scratch"+BS+"x.cs","content":"class X {}"},
     "tool_response":{"success":True}}
open("payload.json","w").write(json.dumps(p))
PY

HOOK=~/.claude/plugins/cache/claude-plugins-official/semgrep/2.1.2/scripts/hook.sh
bash "$HOOK" claude PostToolUse < payload.json

Observed:

{"hookSpecificOutput":{"additionalContext":"Rel: can't make C:\\Users\\me\\scratch\\x.cs relative to D:\\Projects\\App","hookEventName":"PostToolUse"}}

The base is whichever side the process happens to be on, so the error fires in both directions: a D: project writing a C: file, and a C:-rooted process touching a D: file.

Impact

  1. Context pollution: a misleading Rel: can't make … line is fed to the model on every file write. It reads like a real failure, and the agent has no way to tell it is a plugin-internal path bug.
  2. It makes the hook's behaviour on Windows unexplainable from the outside — this error is the only output the hook ever produces here (see the companion issue: Windows: hook binary is inert — every event returns {}, no findings ever, no guardian-cache written #59 — the hook returns {} and reports no findings even when the paths are on the same drive).

Likely fix

Don't relativize for the purpose of opening/scanning a file — filepath.Rel has no valid answer across volumes. If a repo-relative path is needed for reporting, guard it:

rel, err := filepath.Rel(base, file)
if err != nil {
    rel = file // different volume (or otherwise unrelatable): fall back to the absolute path
}

and keep using the absolute path for I/O. A filepath.VolumeName(base) != filepath.VolumeName(file) check up front would make the intent explicit.

Related

Activity

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