Skip to content

fix(serve): degrade startup banner to ASCII on non-UTF-8 consoles (#522)#526

Merged
padak merged 1 commit into
mainfrom
fix/serve-banner-cp1250-crash-522
Jul 22, 2026
Merged

fix(serve): degrade startup banner to ASCII on non-UTF-8 consoles (#522)#526
padak merged 1 commit into
mainfrom
fix/serve-banner-cp1250-crash-522

Conversation

@padak

@padak padak commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #522kbagent serve --ui crashed on startup on Windows with a non-UTF-8
console codepage (e.g. cp1250 on Czech/Polish/Hungarian Windows 11).

The startup banner in commands/serve.py writes box-drawing glyphs (├─ / └─)
via sys.stdout.write. On a legacy single-byte console those glyphs cannot be
encoded, so the write raised UnicodeEncodeError before uvicorn.run was
reached — the server never bound the port. Both the --ui and API-only banner
branches were affected.

Fix

  • Transliterate the box-drawing glyphs to ASCII (|- / `-) when
    sys.stdout.encoding can't represent them. This mirrors the UTF-8/ASCII
    fallback install.sh
    already uses for its own banner (Unicode only under a UTF-8 locale, ASCII
    otherwise).
  • A belt-and-braces try/except UnicodeEncodeError around the write re-emits
    lossily, so a purely cosmetic banner can never abort server startup.
  • Modern UTF-8 terminals are unaffected — the glyphs are kept verbatim.

The banner logic is split into two small helpers to match the existing style in
this module (cf. _default_conversation_id):

  • _encode_safe(text, encoding) — pure transliteration decision, fully unit-testable.
  • _write_banner(text) — the I/O wrapper with the fallback.

Testing

New tests/test_serve_banner_encoding.py (19 tests):

  • A faithful cp1250 stdout fake whose write() raises UnicodeEncodeError on
    the glyphs exactly like a real Windows console — with a fidelity test proving
    the fake reproduces the crash, so the passing case isn't vacuous.
  • Branch coverage for _encode_safe (UTF-8 keeps glyphs; cp1250/cp1252/latin-1/
    ascii transliterate; None encoding; unknown-codec LookupError).
  • _write_banner doesn't crash on cp1250, preserves Unicode on UTF-8, and the
    belt-and-braces path survives a stream that lies about its encoding.
  • An AST-based regression guard: it parses serve_command, extracts the live
    banner = (...) literals, and asserts every non-ASCII glyph they emit has an
    entry in _BANNER_ASCII_FALLBACK — so a future glyph added to the banner
    without a fallback fails CI rather than shipping another crash.

All 69 serve-related tests pass; ruff check, ruff format --check, ty check,
and make changelog-check are green. No command signature changed, so no
plugin/agent-doc sync is required.

Reproduction (before this fix)

set PYTHONUTF8=0
kbagent serve --ui
# UnicodeEncodeError: 'charmap' codec can't encode characters ... cp1250.py

The documented workaround (set PYTHONUTF8=1) is no longer needed.

`kbagent serve --ui` crashed on startup on Windows with a non-UTF-8 console
codepage (e.g. cp1250 on Czech/Polish/Hungarian Windows 11). The startup
banner writes box-drawing glyphs (├─ / └─) via sys.stdout.write, which
raised UnicodeEncodeError before uvicorn.run was reached -- so the server
never bound the port. The same crash hit any legacy single-byte console
encoding.

Transliterate the glyphs to ASCII (|- / `-) when sys.stdout.encoding cannot
represent them, mirroring the UTF-8/ASCII fallback install.sh already uses
for its banner. A belt-and-braces try/except around the write re-emits
lossily so a purely cosmetic banner can never abort startup. Modern UTF-8
terminals are unaffected -- the glyphs are kept verbatim.

The banner build is split into _encode_safe() (pure transliteration
decision) and _write_banner() (the I/O wrapper), both unit-tested; an
AST-based regression test extracts the live banner literals from
serve_command and asserts every glyph they emit has an ASCII fallback, so a
future glyph added without extending the table fails the test.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@padak
padak merged commit 0414927 into main Jul 22, 2026
5 checks passed
@padak
padak deleted the fix/serve-banner-cp1250-crash-522 branch July 22, 2026 16:29
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.

kbagent serve --ui crashes on startup on Windows with non-UTF-8 console codepage (UnicodeEncodeError in banner)

1 participant