Skip to content

fix(cli): force UTF-8 stdout/stderr on Windows to prevent UnicodeEncodeError#2817

Open
rafaelfiguereod-stack wants to merge 1 commit into
github:mainfrom
rafaelfiguereod-stack:fix/windows-utf8-console-encoding
Open

fix(cli): force UTF-8 stdout/stderr on Windows to prevent UnicodeEncodeError#2817
rafaelfiguereod-stack wants to merge 1 commit into
github:mainfrom
rafaelfiguereod-stack:fix/windows-utf8-console-encoding

Conversation

@rafaelfiguereod-stack
Copy link
Copy Markdown

Description

On Windows, specify crashes with UnicodeEncodeError whenever stdout/stderr
are not a UTF-8 TTY — i.e. when output is piped, redirected to a file, or the
console uses a legacy code page (e.g. cp1252). Rich renders the ASCII-art
banner and box-drawing characters, and the default Windows text encoding can't
encode them, so even specify --help and specify version abort with a
traceback instead of printing.

Repro (Windows, default code page):

> specify --help | more
... UnicodeEncodeError: 'charmap' codec can't encode characters ...

Fix: at the main() entry point, on win32 only, reconfigure
sys.stdout/sys.stderr to UTF-8 with errors="replace" so output degrades
gracefully instead of crashing.

  • No-op on POSIX.
  • Guarded by try/except (AttributeError, ValueError, OSError) so unusual
    stream setups (already-wrapped/detached streams) can never make things worse.
  • Placed at the CLI entry point, so importing specify_cli as a library does
    not mutate global streams.
if sys.platform == "win32":
    for _stream in (sys.stdout, sys.stderr):
        try:
            _stream.reconfigure(encoding="utf-8", errors="replace")
        except (AttributeError, ValueError, OSError):
            pass

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (N/A — change only affects console stream encoding)

On Windows 11, cp1252 console, without PYTHONUTF8/PYTHONIOENCODING:

  • specify --help piped → renders banner + option boxes, exit 0 (was: UnicodeEncodeError).
  • specify version > out.txt → renders correctly, exit 0 (was: traceback).

Full suite: 3217 passed, 119 skipped. The 11 failures are pre-existing and
unrelated to this change — os.symlink() calls in test setup raise
OSError [WinError 1314] because the Windows host lacks symlink-create
privilege; they pass on POSIX / elevated Windows.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Diagnosed, implemented, and verified with Claude (Claude Code); reviewed before
submission. Reflected in the commit's Co-Authored-By trailer.

…deError

On Windows, when stdout/stderr are not a UTF-8 TTY (output piped, redirected
to a file, or running under a legacy code page such as cp1252), Rich cannot
encode the banner and box-drawing glyphs, so the CLI aborts with a
UnicodeEncodeError traceback instead of printing. This breaks basic commands
like `specify --help` and `specify version` whenever their output is captured
rather than written to an interactive terminal.

Reconfigure sys.stdout/sys.stderr to UTF-8 with errors="replace" at the
main() entry point on win32 so output degrades gracefully instead of crashing.
The change is a no-op on POSIX, is guarded by try/except so it can never make
stream setup worse, and lives at the CLI entry point only -- importing
specify_cli as a library does not touch global streams.

Verified on Windows 11 (cp1252): `specify --help` piped and `specify version`
redirected to a file both render correctly and exit 0 without setting
PYTHONUTF8 / PYTHONIOENCODING.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prevents UnicodeEncodeError crashes on Windows when specify output is redirected/piped or when the console uses a non‑UTF‑8 code page by reconfiguring sys.stdout/sys.stderr to UTF‑8 at the CLI entry point.

Changes:

  • On Windows (sys.platform == "win32"), call reconfigure(encoding="utf-8", errors="replace") on sys.stdout and sys.stderr before invoking the Typer app.
  • Guard stream reconfiguration with try/except so unusual stream setups don’t introduce new failures.
Show a summary per file
File Description
src/specify_cli/__init__.py Reconfigures stdout/stderr to UTF‑8 on Windows at main() startup to avoid UnicodeEncodeError when printing Rich UI output.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants