Skip to content

UnicodeEncodeError on Windows - cp1252 cannot encode box-drawing characters #65

Description

@Mythikos

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:

  1. CLI banner outputclick.echo() fails to encode Unicode box-drawing characters to stdout (UnicodeEncodeError)
  2. Proxy subprocess — inherits cp1252 encoding and crashes when server.py prints its own Unicode banner
  3. rtk subprocess callssubprocess.run(..., text=True) in installer.py defaults to cp1252 for decoding rtk binary output (UnicodeDecodeError)

To Reproduce

  1. Install headroom on Windows with pip install headroom
  2. Run headroom wrap claude
  3. See the UnicodeEncodeError from the proxy subprocess
  4. 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):

  1. 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")
  1. 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)
  1. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions