claude-code - 💡(How to fix) Fix if field in hooks does not match file-extension patterns — Edit(*.ts) never fires even for TypeScript files [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#49229Fetched 2026-04-17 08:47:08
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Author
Timeline (top)
labeled ×4commented ×1

Root Cause

Root Cause Hypothesis

Fix Action

Workaround

Filter by file extension inside the hook script instead:

file_path=$(cat | jq -r '.tool_input.file_path // empty')
[[ "$file_path" == *.ts ]] || exit 0
# ... rest of hook

Note: bash's [[ == *.ts ]] correctly matches an absolute path suffix, unlike the if field's glob.

Code Example

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "if": "Edit(*.ts)|Write(*.ts)",
            "command": "echo $(date) >> /tmp/if-hook-test.log"
          }
        ]
      }
    ]
  }
}

---

cat /tmp/if-hook-test.log

---

/Users/alice/project/src/app.ts

---

"Read(//Users/alice/project/**)"

---

file_path=$(cat | jq -r '.tool_input.file_path // empty')
[[ "$file_path" == *.ts ]] || exit 0
# ... rest of hook
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported
  • This is a single bug report
  • I am using the latest version of Claude Code

What's Wrong?

The docs state:

"Edit(*.ts)" runs only for TypeScript files

In practice, a hook with if: "Edit(*.ts)" never fires, including when Claude edits a .ts file. Removing the if field causes the hook to fire correctly. The if condition appears to always evaluate to false for file-path patterns.

Environment

  • Claude Code version: 2.1.110
  • OS: macOS (Darwin 25.3.0)
  • Shell: zsh

Minimal Reproduction

1. Add to ~/.claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "if": "Edit(*.ts)|Write(*.ts)",
            "command": "echo $(date) >> /tmp/if-hook-test.log"
          }
        ]
      }
    ]
  }
}

2. In a Claude Code session, ask Claude to edit any .ts file.

3. Check the log:

cat /tmp/if-hook-test.log

Expected: A timestamp appears — the hook ran for a TypeScript file. Actual: The file is never created. The hook never fires.

4. Confirm the hook system works without if:

Remove the if line and repeat step 2. The timestamp appears in the log. This rules out any issue with the hook command itself.

Root Cause Hypothesis

Claude Code's Edit and Write tools always pass file_path as a full absolute path, e.g.:

/Users/alice/project/src/app.ts

The permission rule Edit(*.ts) uses a glob where * does not match path separators (/), so it never matches an absolute path. The if condition always evaluates to false, and the hook is silently skipped.

This is consistent with the rest of the permission rule system, where absolute paths require a // prefix and recursive matching requires **:

"Read(//Users/alice/project/**)"

If Edit(*.ts) is intended as a suffix/basename check (matching any file ending in .ts regardless of path), the glob matching logic needs to be updated to handle it that way.

Expected Behaviour

Per the docs, "Edit(*.ts)" should match any Edit tool call where the target file ends in .ts, at any path depth.

Either:

  • Fix glob matching so *.ts is a suffix check against the filename or full path, or
  • Clarify in the docs that Edit(**/*.ts) is required for matching files in subdirectories

Workaround

Filter by file extension inside the hook script instead:

file_path=$(cat | jq -r '.tool_input.file_path // empty')
[[ "$file_path" == *.ts ]] || exit 0
# ... rest of hook

Note: bash's [[ == *.ts ]] correctly matches an absolute path suffix, unlike the if field's glob.

Additional Context

  • The if field was added in v2.1.85. This may be a regression, or the file-path case may never have been implemented correctly.
  • The one confirmed fix (v2.1.88) was specific to compound Bash commands (ls && git push) and env-var prefixes — not file-path patterns.
  • #36332: A feature request to add argument-pattern filtering to matcher — the community workaround suggested was script-level filtering, not if. This suggests if with file patterns is not well-known as a working solution.

extent analysis

TL;DR

The if condition in Claude Code's hook system does not correctly match file paths with the *.ts glob pattern, requiring a workaround or update to the glob matching logic.

Guidance

  • The issue is likely due to the *.ts glob pattern not matching absolute paths, which can be verified by checking the file path passed by the Edit and Write tools.
  • To mitigate this, the workaround provided in the issue can be used, which filters by file extension inside the hook script using bash's [[ == *.ts ]] syntax.
  • Another possible solution is to update the glob matching logic to handle suffix checks against the filename or full path.
  • The documentation should be clarified to reflect the correct usage of the if field with file-path patterns, such as requiring Edit(**/*.ts) for matching files in subdirectories.

Example

file_path=$(cat | jq -r '.tool_input.file_path // empty')
[[ "$file_path" == *.ts ]] || exit 0
# ... rest of hook

This example shows how to filter by file extension inside the hook script using bash's [[ == *.ts ]] syntax.

Notes

The issue may be a regression introduced in version 2.1.85, and the confirmed fix in version 2.1.88 does not address file-path patterns. The community workaround suggested in #36332 also uses script-level filtering, not the if field.

Recommendation

Apply the workaround by filtering by file extension inside the hook script, as it is a reliable and immediate solution to the issue. This approach allows for correct matching of file paths with the *.ts pattern until the glob matching logic is updated.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING