From e72abb593da7af6f1600b207cd378ef4656541f6 Mon Sep 17 00:00:00 2001 From: LHMQ878 <72402929@cityu-dg.edu.cn> Date: Mon, 27 Jul 2026 18:31:31 +0800 Subject: [PATCH] Fix UnicodeEncodeError in print_banner when stdout is non-UTF-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The startup banner contains '➜' (U+279C). When stdout is redirected to a file or pipe on Windows, Python uses the system locale encoding (e.g. GBK/cp936) instead of UTF-8, so printing the banner raises UnicodeEncodeError and kills the process before the web server binds its port. Wrap banner output in a _safe_print helper that falls back to the stream's encoding with errors='replace' on UnicodeEncodeError, so startup continues regardless of stdout encoding. UTF-8 terminals are unaffected. Fixes #2532 --- src/kimi_cli/utils/server.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/kimi_cli/utils/server.py b/src/kimi_cli/utils/server.py index a33186ace5..30658f1e5d 100644 --- a/src/kimi_cli/utils/server.py +++ b/src/kimi_cli/utils/server.py @@ -4,6 +4,7 @@ import importlib import socket +import sys import textwrap @@ -86,6 +87,25 @@ def get_network_addresses() -> list[str]: return addresses +def _safe_print(text: str) -> None: + """Print *text*, degrading gracefully when stdout can't encode a character. + + When stdout is redirected to a file or pipe on Windows, Python uses the + system locale encoding (e.g. GBK/cp936) instead of UTF-8. Banner characters + such as ``➜`` (U+279C) are not representable there, so a plain ``print`` + raises ``UnicodeEncodeError`` and kills the process before the server binds + its port. Fall back to the stream's encoding with ``errors="replace"`` so + the banner still prints (with a placeholder) and startup continues. + """ + try: + print(text) + except UnicodeEncodeError: + stream = sys.stdout + encoding = getattr(stream, "encoding", None) or "utf-8" + safe = text.encode(encoding, errors="replace").decode(encoding) + print(safe) + + def print_banner(lines: list[str]) -> None: """Print a boxed banner with tag conventions (