Skip to content

[BUG] Hook if field: path patterns with explicit / separators never match on Windows #67610

@dorcon0000-eng

Description

@dorcon0000-eng

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

In hook if conditions, file-path patterns containing an explicit / separator (e.g. Write(subdir/**), Write(**/subdir/inner/**)) never match on Windows — the hook silently never fires. Only globstar-pure patterns without any / (e.g. Write(**subdir**), Write(**.py)) match. Matching is also case-sensitive (Write(**SUBDIR**) does not match subdir), while Windows paths are not.

This is not the permission-engine path bug fixed in 2.1.162 ("permission rules backslash/case"): since that release, allow/deny permission rules match Windows paths correctly, but the hook if field still fails — the two matchers appear to be separate engines. Existing issues #64432 / #55674 cover the permission-engine side only.

The docs state the if field "accepts the same patterns as permission rules: Bash(git *), Edit(*.ts)" — with no Windows caveat, so this looks like a genuine bug rather than documented behavior.

Deterministic across repeated runs; reproduced on 2.1.143, 2.1.162, 2.1.165, 2.1.167 and 2.1.173.

What Should Happen?

All path patterns that match the written file should fire their hooks. For a Write of subdir/inner/config.py, the spies with if: "Write(subdir/**)" and if: "Write(**/subdir/inner/**)" should fire exactly like the globstar-pure if: "Write(**subdir**inner**)" does (and matching should arguably be case-insensitive on Windows, since the filesystem is).

Error Messages/Logs

No error output — the failure is silent: hooks with `/`-containing patterns simply never run.

markers.log after the repro run (only globstar-pure + catch-all fired):
M_GLOBSTAR
ALL

Steps to Reproduce

  1. On Windows, create a sandbox folder (e.g. C:\hooktest\) with .claude\settings.json:
{
  "permissions": { "allow": ["Write(*)", "Read(*)"] },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          { "type": "command", "command": "bash .claude/spy.sh M_GLOBSTAR", "if": "Write(**subdir**inner**)" },
          { "type": "command", "command": "bash .claude/spy.sh S_SLASH",    "if": "Write(subdir/**)" },
          { "type": "command", "command": "bash .claude/spy.sh S_SLASH2",   "if": "Write(**/subdir/inner/**)" },
          { "type": "command", "command": "bash .claude/spy.sh CASE",       "if": "Write(**SUBDIR**INNER**)" },
          { "type": "command", "command": "bash .claude/spy.sh ALL",        "if": "Write(**)" }
        ]
      }
    ]
  }
}
  1. Create .claude/spy.sh (marker side-effect on the filesystem):
#!/bin/bash
cat >/dev/null 2>&1
printf '%s\n' "$1" >> markers.log
exit 0
  1. Run headless (prompt via stdin so $()/globs are not expanded by the outer shell):
cd /c/hooktest
echo 'Use the Write tool to create the file subdir/inner/config.py containing exactly: # hook matcher test. Do nothing else.' | claude -p --permission-mode bypassPermissions --allowedTools Write > /dev/null
cat markers.log
  1. Expected: M_GLOBSTAR, S_SLASH, S_SLASH2, ALL (plus CASE if matching were case-insensitive).
    Actual: only M_GLOBSTAR and ALL — every pattern containing / (relative or anchored) never fires, CASE never fires.

Claude Model

None

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

2.1.173 (Claude Code)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

  • Model-independent (the if matcher runs in the harness around the tool call); reproduced with multiple models.
  • Native Windows install; hooks run via Git Bash (bare bash on PATH).
  • Current workaround: globstar-pure patterns without / (e.g. Edit(**myproject**src**)), treated as case-sensitive.
  • We maintain a spy-hook test bench and have re-verified this on every recent release — happy to provide further matrices.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:hooksbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:windowsIssue specifically occurs on Windows

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions