claude-code - 💡(How to fix) Fix [BUG] Worktree creation (-w) sets LC_ALL=C in hook subprocess, breaking UTF-8 handling in git hooks

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…

Error Message

ArgumentError: invalid byte sequence in US-ASCII

Fix Action

Fix / Workaround

Workarounds (for users hitting this):

Code Example

$ LC_ALL=C ruby -e 'puts Encoding.default_external'
US-ASCII

---

ArgumentError: invalid byte sequence in US-ASCII

---

ArgumentError: invalid byte sequence in US-ASCII

---

LANG=en_US.UTF-8
LC_ALL=C        ← injected by harness; unset in parent shell
AI_AGENT=claude-code_2-1-136_harness

---

#!/bin/sh
   env | sort > /tmp/hook-env.log

---

claude -w

---

spawn('git', ['worktree', 'add', ...], { env: { ...process.env, LC_ALL: 'C' } })

---

2.1.136
RAW_BUFFERClick to expand / collapse

Preflight Checklist

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

What's Wrong?

In Claude Code 2.1.136, the subprocess that runs git hooks during worktree creation (claude -w) has LC_ALL=C set in its environment, even though the parent shell that launched claude has LC_ALL unset (and LANG=en_US.UTF-8).

LC_ALL overrides LANG, so for any locale-aware program invoked from a hook, the effective locale becomes C (ASCII). This silently breaks UTF-8 file handling in post-checkout hooks. For example, with Ruby:

$ LC_ALL=C ruby -e 'puts Encoding.default_external'
US-ASCII

so File.read('utf8_file_with_japanese.md') returns a US-ASCII-tagged String, and a subsequent regex match against multibyte content raises:

ArgumentError: invalid byte sequence in US-ASCII

Any post-checkout hook that processes UTF-8 files (e.g., reading YAML frontmatter from .md files) silently fails as a result.

This is a regression: the same hooks worked correctly on 2.1.133 and broke on 2.1.136.

What Should Happen?

LC_ALL should not be force-set to C in the env that user-defined git hooks see. It should be inherited from the parent shell (i.e., remain unset in this user's case), so locale-aware programs in hooks behave the same as in a normal terminal session — as was the case on 2.1.133.

Error Messages/Logs

ArgumentError: invalid byte sequence in US-ASCII

Hook env capture (/tmp/hook-env.log) shows:

LANG=en_US.UTF-8
LC_ALL=C        ← injected by harness; unset in parent shell
AI_AGENT=claude-code_2-1-136_harness

Steps to Reproduce

  1. Install a tiny post-checkout hook in the source repo (the one you'll create the worktree from):
    #!/bin/sh
    env | sort > /tmp/hook-env.log
    Make it executable (chmod +x .git/hooks/post-checkout).
  2. From a shell where LC_ALL is unset and LANG=en_US.UTF-8, run:
    claude -w
  3. After the worktree is created, inspect /tmp/hook-env.log. You will see LC_ALL=C set, despite it being unset in the parent shell.
  4. To confirm the user-visible breakage, replace the hook body with a Ruby script that reads a UTF-8 file containing multibyte characters and runs a regex match — it raises ArgumentError: invalid byte sequence in US-ASCII.
  5. Downgrading to 2.1.133 makes the same hook see the parent's locale (no LC_ALL=C injection), and the Ruby script succeeds.

Hypothesis

LC_ALL=C is a common pattern when invoking git programmatically (it stabilises git's stdout/stderr in English so it's parseable). If the harness is doing something like:

spawn('git', ['worktree', 'add', ...], { env: { ...process.env, LC_ALL: 'C' } })

then the hooks git runs inherit that env. Scoping LC_ALL=C to the output processing of the direct git invocation only (e.g., piping git's stdout through a wrapper that sets LC_ALL=C for its own decoding logic, while letting git itself — and its hooks — run under the user's locale) would restore prior behaviour.

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.133

Claude Code Version

2.1.136

Platform

Anthropic API

Operating System

macOS (Darwin arm64)

Terminal/Shell

Other: Ghostty (zsh)

Additional Information

Workarounds (for users hitting this):

  • Set Encoding.default_external = Encoding::UTF_8 explicitly at the top of any Ruby hook script.
  • Or export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 inside the hook before invoking interpreters.
  • Pin Claude Code to 2.1.133 until this is fixed.

Asks:

  • Confirmation of whether this LC_ALL=C injection is intentional.
  • If intentional, a changelog note / docs page advising hook authors to be locale-defensive would help.
  • If unintentional, scoping the override to git's own output handling (not its child processes) would restore prior behaviour.

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

claude-code - 💡(How to fix) Fix [BUG] Worktree creation (-w) sets LC_ALL=C in hook subprocess, breaking UTF-8 handling in git hooks