Skip to content

fix: PowerShell output encoding for non-ASCII characters on Windows #23636

Closed as not planned

Description

@l1i1

Bug description

On Windows systems with Chinese/Japanese/Korean locales, non-ASCII characters (e.g., Chinese filenames) appear garbled in the output of PowerShell commands executed through the bash tool. This happens because [Console]::OutputEncoding defaults to system encoding (e.g., GB2312 code page 936 for Chinese Windows) while the terminal expects UTF-8 output.

Reproduction

  1. Use Windows with Chinese locale (or any non-UTF-8 locale)
  2. Run OpenCode
  3. Execute ls "path-with-chinese-filenames" via bash tool
  4. Observe garbled output like ʼ for 笔记

Expected behavior

Non-ASCII characters should display correctly as UTF-8 in bash tool output.

Environment

  • OS: Windows 10/11
  • Shell: PowerShell / pwsh
  • Locale: zh-CN, ja-JP, ko-KR

Root cause

The cmd() function spawns PowerShell with -NoProfile flag, which prevents loading user's profile. Meanwhile, [Console]::OutputEncoding defaults to system encoding (GB2312/GBK), causing UTF-8 output to be misinterpreted.

Proposed fix

Prepend UTF-8 encoding setting to the PowerShell command:

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; <original command>

Activity

  1. added
    bugSomething isn't working
    on Apr 21, 2026
  2. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Apr 21, 2026
  3. fkyah3 commented on Apr 24, 2026

    @fkyah3

    I have this fix running in production on my fork. A few notes:

    [Console]::OutputEncoding alone is not enough. Three encoding layers need to be set for PowerShell:

    Setting Scope
    chcp 65001 Console code page
    [Console]::OutputEncoding .NET output encoding
    $OutputEncoding PowerShell pipeline encoding

    cmd.exe also needs the same fix. The cmd() function has two branches:

    1. PS.has(name) -> PowerShell: needs all three settings
    2. Otherwise -> cmd.exe: needs chcp 65001 > nul && prefix

    Without the cmd.exe branch fix, commands that fall through to cmd.exe will still produce garbled output.

    Working implementation (one file, packages/opencode/src/tool/bash.ts):
    https://github.com/fkyah3/opencode-fkyah3/blob/pr/cjk-encoding-fix/packages/opencode/src/tool/bash.ts

    Hope this helps land the fix.

  4. Hona commented on Apr 24, 2026

    @Hona
    Member

    nice @fkyah3 would you mind submiting a PR and @ ing me ? I can merge it asap

    would be legendary to show before/after screenshot if possible

  5. fkyah3 commented on Apr 24, 2026

    @fkyah3

    @Hona thanks! My repo doesn't seem to be registered as a fork of anomalyco/opencode (I made it private then public earlier), so gh pr create gives me a "head ref invalid" error.

    The branch with the fix is here:
    https://github.com/fkyah3/opencode-fkyah3/tree/pr/cjk-encoding-fix

    And the convenient PR link (just need to change base repo to anomalyco/opencode):
    https://github.com/fkyah3/opencode-fkyah3/pull/new/pr/cjk-encoding-fix

    Or if you prefer, you can cherry-pick the single commit directly:
    https://github.com/fkyah3/opencode-fkyah3/commit/be3d23604628975a6da7a4ade9fc0f03cb4ac8a5

    The fix is one file, 11 insertions, 2 deletions. I've been running it in production for days without issues.

    And full credit to my AI agent (Sisyphus / DeepSeek v4Lite) for finding the root cause and implementing the fix - I just pressed the buttons :)

  6. Hona commented on Apr 24, 2026

    @Hona
    Member

    gotcha - but to confirm you've visually seen the issue - and after this fix the visuals are fine to you (e.g. have you manually tested it)

  7. fkyah3 commented on Apr 24, 2026

    @fkyah3

    @Hona yes, confirmed visually — I'm the one who was staring at garbled Chinese text every day before the fix. We've been running this in my local fork for days:

    • Before: Write-Output "你好世界" outputs ä½ å¥½ä¸ç\U+fffd\U+fffd (garbled GBK interpreted as UTF-8)
    • After: Same command outputs 你好世界 (correct)

    I've tested both PowerShell commands and cmd.exe commands on Windows 11 with zh-CN locale. Both work correctly with the fix.

    Only reason I didn't attach a screenshot is that my AI agent (Sisyphus) did the actual implementation — I described the problem, it wrote the fix, I tested it. Happy to take a screenshot if you need one.

  8. fkyah3 commented on Apr 24, 2026

    @fkyah3

    @Hona sorry about that — the repo isn't registered as an official fork so GitHub redirects are wonky.

    Working links:

    Commit diff: https://github.com/fkyah3/opencode-fkyah3/commit/be3d23604628975a6da7a4ade9fc0f03cb4ac8a5

    File (single-file change): https://github.com/fkyah3/opencode-fkyah3/blob/pr/cjk-encoding-fix/packages/opencode/src/tool/bash.ts#L282-L298

    The easiest route: just cherry-pick the single commit into your fork:
    git remote add fkyah3 https://github.com/fkyah3/opencode-fkyah3 git fetch fkyah3 pr/cjk-encoding-fix git cherry-pick be3d23604628975a6da7a4ade9fc0f03cb4ac8a5

    11 insertions, 2 deletions, one file. I've been running it for days without issues on Windows 11 zh-CN.

  9. fkyah3 commented on Apr 24, 2026

    @fkyah3

    @Hona here's the exact diff. One file, packages/opencode/src/tool/bash.ts, cmd() function. 11 insertions, 2 deletions. Just copy-paste this into the file:

    diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts
    index 0a7e1a6dc..0ee2420c5 100644
    --- a/packages/opencode/src/tool/bash.ts
    +++ b/packages/opencode/src/tool/bash.ts
    @@ -279,7 +279,11 @@ function cmd(shell, name, command, cwd, env) {
       if (process.platform === "win32" && PS.has(name)) {
    -    return ChildProcess.make(shell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", command], {
    +    // chcp alone is insufficient: PowerShell's [Console]::OutputEncoding and
    +    // $OutputEncoding also default to the system ANSI code page (e.g. 936 GBK
    +    // on Chinese Windows), garbling CJK output when read as UTF-8.
    +    const psPrefix = "chcp 65001 > $null; [Console]::OutputEncoding = [Text.UTF8Encoding]::new(); $OutputEncoding = [Text.UTF8Encoding]::new(); "
    +    return ChildProcess.make(shell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", `${psPrefix}${command}`], {
           cwd,
           env,
           stdin: "ignore",
    @@ -287,7 +291,12 @@ function cmd(shell, name, command, cwd, env) {
         })
       }
     
    -  return ChildProcess.make(command, [], {
    +  // On Windows, chcp 65001 is NOT inherited from the parent process.
    +  // Each spawned cmd.exe gets the system default code page (e.g. 936 GBK),
    +  // which garbles Chinese/CJK output when read as UTF-8.
    +  // For cmd.exe, chcp is sufficient (no .NET encoding layer to fix).
    +  const cmdPrefix = process.platform === "win32" ? "chcp 65001 > nul && " : ""
    +  return ChildProcess.make(`${cmdPrefix}${command}`, [], {
         shell,
         cwd,
         env,
  10. wqerrewetw commented on May 1, 2026

    @wqerrewetw

    A temporary fix .
    First, create a pwsh.cmd file.

    @echo off
    chcp 65001 >nul
    pwsh.exe   %*

    Then, set the shell in opencode.jsonc.

    "shell": "path/to/you/pwsh.cmd",
    Image Image
  11. 3 remaining items

  12. cpt-sd76vg commented on Jun 24, 2026

    @cpt-sd76vg

    I ended up writing a small wrapper in Go just to work around this issue by bypassing the problem and launching pwsh. I hope this gets fixed soon.

  13. skywalker-35 commented on Jun 26, 2026

    @skywalker-35

    +1 workaround verified on Windows 11 zh-CN.

    Just implemented the pwsh.cmd wrapper from wqerrewetw's earlier comment in this thread:

    @echo off
    chcp 65001 >nul
    pwsh.exe %*

    Set as "shell": "C:/Users/leewe/.config/opencode/pwsh.cmd" in opencode.jsonc.

    Before (with "shell": "pwsh.exe"): Chinese filenames return garbled bytes like �������ı���
    After (with pwsh.cmd wrapper): Same command returns 测试中文编码:你好世界 笔记材料 仓库库存 correctly

    Also confirming fkyah3's analysis in this thread — the three-layer fix (chcp + [Console]::OutputEncoding + $OutputEncoding) is needed for full PowerShell coverage; the cmd.exe-only chcp prefix in his diff handles the non-PowerShell branch.

    @Hona since fkyah3's fork isn't registered as an official fork (#23636 (comment)), can you or another maintainer cherry-pick commit be3d23604628975a6da7a4ade9fc0f03cb4ac8a5 into a feature branch and open the PR? 11 lines, 1 file, already validated on zh-CN and ru-RU. This would unblock zh/ja/ko/ru users who currently have to use either this pwsh.cmd wrapper or fork the repo.

  14. cpt-sd76vg commented on Jun 26, 2026

    @cpt-sd76vg

    Just a heads-up: a cmd-based wrapper may appear to work at first, but going through cmd.exe can introduce its own issues. In particular, parts of the command line, such as double quotes and other quoting/escaping-sensitive characters, may be consumed or reinterpreted by cmd, which can cause subtle bugs.

    That is why I ended up writing a small Go-based wrapper instead.

    There is also already an active PR for this: #31985. I used the code in that PR as a reference when implementing my Go wrapper locally, and it worked well in my environment.

  15. id5463 commented on Aug 11, 2026

    @id5463

    Hi maintainers, following up on this issue — it is still not fixed as of the latest installed release (1.18.15) and affects every zh-CN / ja-JP / ko-KR Windows user.

    Verified reproduction (Windows 11, zh-CN, ACP=936, via the opencode bash tool):

    Write-Output '中文测试123'
    # → ���IJ���123          (mojibake)
    
    [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Write-Output '中文测试123'
    # → 中文测试123          (correct)

    Root cause confirmed on my machine: opencode spawns powershell.exe with -NoProfile, so user profiles cannot set [Console]::OutputEncoding; PowerShell inherits the system code page (GBK/936); opencode hardcodes UTF-8 decoding of captured stdout → mojibake. Note chcp 65001 alone does not fix redirected (piped) output — only explicitly setting [Console]::OutputEncoding does.

    Concern: all four fix PRs were closed without being merged:

    And #31187 was auto-closed by the 60-day inactivity bot while the bug still exists.

    Could the maintainers please merge #31985 (or land an equivalent fix in the shell wrapper) and ship it? This blocks CJK Windows users from reliably using PowerShell in the bash tool. Happy to help test a fix if needed.

    Workaround for reference: prefix commands with [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; or use an external wrapper (e.g. pwsh-utf8-wrapper).

  16. Bigzhangbig commented on Sep 29, 2026

    @Bigzhangbig

    Verified data point that contradicts one of the premises in this thread, in case it saves a rebase.

    Env: Windows 11, zh-CN (ACP/OEMCP = 936) · PowerShell 7.6.6 (not 5.1) · opencode v2.0.18 (windows-x64)

    @Astro-Han suggested in #30055 not to inject [Console]::OutputEncoding for PS7 because "PowerShell 7+ already defaults to UTF-8". On zh-CN that doesn't hold — neither with stdout piped nor with a real console attached:

    # stdout piped (how opencode runs it)
    PS> [Console]::OutputEncoding.CodePage   # 936
    PS> [Console]::OutputEncoding.WebName    # gb2312
    
    # fresh conhost window, no redirection
    936|gb2312
    

    GetConsoleOutputCP() returns the NLS OEMCP, so the parent process doesn't matter. The gate needs to be "Windows", not "PS version".

    End-to-end through the bash tool on v2.0.18 — before the fix, cmd /c "echo 测试中文" returned ��������; after, 测试中文.

    This confirms @fkyah3's three-layer table: all of chcp 65001, [Console]::OutputEncoding, $OutputEncoding are required.

    Two things that do not work (both tested today):

    • $PROFILE — opencode spawns ["-NoLogo","-NoProfile","-NonInteractive","-Command", cmd], so profiles never load
    • HKCU\Console\CodePage = 65001 — only affects newly allocated consoles, not already-redirected children

    Working no-patch workaround: the shell config option is honoured. Note the pwsh.cmd variant posted earlier in this thread re-interprets quoting through cmd.exe, and Bun's spawn flattens the args into "/c,echo ..." — an .exe wrapper avoids both.

    For a rebase on v2: the arg builder is now a single fU() shared by the bash tool and the TUI, so Shell.args() / tool/shell.ts:cmd() no longer exist as separate functions.

    Written with opencode v2.0.18. Every number above is measured on my own machine, and the wrapper is what I'm actually running.

  17. xiaozhu1337 commented on Oct 3, 2026

    @xiaozhu1337

    Still broken on v2.0.22 (windows-x64), confirmed today on Windows zh-CN (ACP/OEMCP 936), shell = pwsh 7.6.6.

    [Console]::OutputEncoding.CodePage  -> 936
    [Console]::OutputEncoding.WebName   -> gb2312
    Write-Output '中文测试你好世界'      -> ���IJ����������
    

    Root cause unchanged (spawned with -NoProfile, so no profile can set [Console]::OutputEncoding; opencode decodes stdout as UTF-8). Fix PR #31658 (open since 2026-06-10) is still not merged.

    Immediate workaround (no core patch needed): install the V2 plugin opencode-windows-encoding:

    opencode plugin add opencode-windows-encoding
    

    It hooks shell create.before and injects the UTF-8 prefix (chcp 65001 / [Console]::OutputEncoding / PYTHONIOENCODING). Verified working on v2.0.22: Chinese shell output is correct after a restart.

  18. 627-hub commented on Oct 11, 2026

    @627-hub

    Confirmed on another setup — adding local case data.

    Environment

    • OS: Windows, zh-CN locale, system code page 936 (GBK)
    • App: OpenCode Desktop 1.19.0
    • Shell: Windows PowerShell 5.1, spawned as:
      powershell.exe -NoLogo -NoProfile -NonInteractive -Command ...

    Repro (bash tool)

    • Command: "中文测试: 远程服务器返回错误: (404) 未找到"
    • Output: ���IJ���: Զ�̷��������ش���: (404) δ�ҵ� (GBK bytes decoded as UTF-8)

    Measured inside the spawned process

    • chcp → 936, [Console]::OutputEncoding.WebName → gb2312
    • -NoProfile means the user profile (Microsoft.PowerShell_profile.ps1) never loads, so it cannot fix the encoding
    • Prepending the fix manually makes output correct — confirms the proposed direction:
      [Console]::OutputEncoding=[Text.Encoding]::UTF8; $OutputEncoding=[Text.Encoding]::UTF8; <original command>

    Workaround attempt via plugin (data point for the fix)
    Using a tool.execute.before plugin hook to inject the prefix:

    • shell.env hook mutations work: injected PYTHONIOENCODING/PYTHONUTF8 reach child processes (verified sys.stdout.encoding == utf-8 in python spawned by the bash tool)
    • injecting the UTF-8 prefix into output.args.command — being verified now; will follow up in this thread

    Also worth noting: the same prefix approach is shipped as the npm plugin opencode-windows-encoding, so there is already community demand for this to land natively (PR #31658).

  19. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions