[BUG] hookify rule files containing non-ASCII are silently skipped on Windows (open() without encoding)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
plugins/hookify/core/config_loader.py opens rule files with open(file_path, 'r') and no encoding, so Python uses the locale default. On Windows that is cp1252, and a rule file containing any byte cp1252 cannot map raises UnicodeDecodeError. That subclasses ValueError, so it is swallowed by the except (ValueError, KeyError, AttributeError, TypeError) handler in load_rule_file, which returns None. The rule is dropped and the hook proceeds.
This defeats action: block rules. The plugin's own shipped examples/dangerous-rm.local.md contains a warning emoji (e2 9a a0 ef b8 8f), so following the documented example produces a block rule that never blocks.
This is separate from #81448, and it affects the copy in this repo and the one in anthropics/claude-plugins-official equally; neither passes an encoding.
What Should Happen?
Rule files should be read as UTF-8 regardless of platform locale, so a rule containing non-ASCII characters loads and is enforced.
Error Messages/Logs
Error: Malformed rule file .claude\hookify.dangerous-rm.local.md: 'charmap' codec can't decode byte 0x8f in position 97: character maps to <undefined>
This goes to stderr. stdout carries no indication that a rule was dropped.
Steps to Reproduce
- Copy the plugin's own example in as a rule:
plugins/hookify/examples/dangerous-rm.local.mdto<project>/.claude/hookify.dangerous-rm.local.md. It isaction: blockon patternrm\s+-rf. - On Windows, feed a matching PreToolUse payload to the hook script:
````
{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"rm -rf /"},"cwd":"<project>","session_id":"t"}
- Observed: stdout is
{}, so the command is allowed. stderr shows the charmap error above. - Change
core/config_loader.py:251toopen(file_path, 'r', encoding='utf-8')and repeat. - Observed:
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny"}, ...}and the rule fires as documented.
This reproduces where the locale default is not UTF-8. On macOS/Linux with a UTF-8 locale it does not, which is likely why it has gone unreported.
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Claude Code Version
2.1.238
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other
Additional Information
Python 3.13, locale.getpreferredencoding(False) returns cp1252. Python 3.15 makes UTF-8 mode the default (PEP 686), which would mask this. hookify 0.1.0, installed from the claude-code-plugins marketplace.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗