Description
On Windows, headroom wrap claude (and other wrap subcommands) crashes with multiple Unicode encoding errors because the default Windows codepage (cp1252) cannot handle UTF-8 content. This affects three areas from my testing:
- CLI banner output —
click.echo() fails to encode Unicode box-drawing characters to stdout (UnicodeEncodeError)
- Proxy subprocess — inherits cp1252 encoding and crashes when
server.py prints its own Unicode banner
- rtk subprocess calls —
subprocess.run(..., text=True) in installer.py defaults to cp1252 for decoding rtk binary output (UnicodeDecodeError)
To Reproduce
- Install headroom on Windows with
pip install headroom
- Run
headroom wrap claude
- See the
UnicodeEncodeError from the proxy subprocess
- Even after working around that,
_setup_rtk() triggers a UnicodeDecodeError when verifying or registering the rtk binary
Expected Behavior
The CLI banner renders correctly, the proxy starts normally, and rtk installs/registers without encoding errors.
Actual Behavior
Error 1: CLI banner / proxy subprocess (UnicodeEncodeError):
The issue is in headroom/cli/wrap.py (lines 393-395) and headroom/proxy/server.py (the startup banner), as well as the generic _launch_tool() (lines 304-306):
# These lines fail on Windows when stdout encoding is cp1252
click.echo(" ╔═══════════════════════════════════════════════╗")
click.echo(" ║ HEADROOM WRAP: CLAUDE ║")
click.echo(" ╚═══════════════════════════════════════════════╝")
Additionally, _start_proxy() launches the proxy subprocess without setting PYTHONIOENCODING, so the subprocess inherits the same cp1252 encoding and crashes when server.py prints its own Unicode banner.
Error 2: rtk installer (UnicodeDecodeError):
In headroom/rtk/installer.py, both download_rtk() (line 123) and register_claude_hooks() (line 151) use subprocess.run(..., text=True) without specifying an encoding, so Python defaults to cp1252 when decoding the rtk binary's output.
Code Sample
Suggested fix (three parts):
- At the top of
wrap.py (or in the CLI entrypoint), reconfigure stdout/stderr to use UTF-8 on Windows:
import io, sys
if sys.platform == "win32" and hasattr(sys.stdout, "buffer"):
if sys.stdout.encoding and sys.stdout.encoding.lower().replace("-", "") != "utf8":
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
- In
_start_proxy(), pass PYTHONIOENCODING=utf-8 in the subprocess environment:
proxy_env = os.environ.copy()
proxy_env["PYTHONIOENCODING"] = "utf-8"
proc = subprocess.Popen(cmd, stdout=log_file, stderr=log_file, env=proxy_env)
- In
installer.py, add encoding="utf-8", errors="replace" to both subprocess.run() calls:
result = subprocess.run(
[str(RTK_BIN_PATH), "--version"],
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
timeout=5,
)
Error Output
Error 1:
Starting Headroom proxy on port 8787...
Error: Proxy exited with code 1: ta\Local\Python\pythoncore-3.14-64\Lib\site-packages\click\utils.py", line 321, in echo
file.write(out) # type: ignore
~~~~~~~~~~^^^^^
File "C:\Users\vlakatos\AppData\Local\Python\pythoncore-3.14-64\Lib\encodings\cp1252.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'charmap' codec can't encode characters in position 2-74: character maps to <undefined>
Error 2:
Setting up rtk...
Exception in thread Thread-2 (_readerthread):
Traceback (most recent call last):
File "...\threading.py", line 1082, in _bootstrap_inner
self._context.run(self.run)
File "...\threading.py", line 1024, in run
self._target(*self._args, **self._kwargs)
File "...\subprocess.py", line 1613, in _readerthread
buffer.append(fh.read())
File "...\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x8f in position 5: character maps to <undefined>
Environment
- Headroom version: 0.5.7
- Python version: 3.14.3
- OS: Windows 11
- LLM Provider: Anthropic
Description
On Windows,
headroom wrap claude(and other wrap subcommands) crashes with multiple Unicode encoding errors because the default Windows codepage (cp1252) cannot handle UTF-8 content. This affects three areas from my testing:click.echo()fails to encode Unicode box-drawing characters to stdout (UnicodeEncodeError)server.pyprints its own Unicode bannersubprocess.run(..., text=True)ininstaller.pydefaults to cp1252 for decoding rtk binary output (UnicodeDecodeError)To Reproduce
pip install headroomheadroom wrap claudeUnicodeEncodeErrorfrom the proxy subprocess_setup_rtk()triggers aUnicodeDecodeErrorwhen verifying or registering the rtk binaryExpected Behavior
The CLI banner renders correctly, the proxy starts normally, and rtk installs/registers without encoding errors.
Actual Behavior
Error 1: CLI banner / proxy subprocess (
UnicodeEncodeError):The issue is in
headroom/cli/wrap.py(lines 393-395) andheadroom/proxy/server.py(the startup banner), as well as the generic_launch_tool()(lines 304-306):Additionally,
_start_proxy()launches the proxy subprocess without settingPYTHONIOENCODING, so the subprocess inherits the same cp1252 encoding and crashes whenserver.pyprints its own Unicode banner.Error 2: rtk installer (
UnicodeDecodeError):In
headroom/rtk/installer.py, bothdownload_rtk()(line 123) andregister_claude_hooks()(line 151) usesubprocess.run(..., text=True)without specifying an encoding, so Python defaults to cp1252 when decoding the rtk binary's output.Code Sample
Suggested fix (three parts):
wrap.py(or in the CLI entrypoint), reconfigure stdout/stderr to use UTF-8 on Windows:_start_proxy(), passPYTHONIOENCODING=utf-8in the subprocess environment:installer.py, addencoding="utf-8", errors="replace"to bothsubprocess.run()calls:Error Output
Error 1:
Error 2:
Environment