Skip to content

fix: gateway.cmd launcher garbles non-ASCII profile paths on non-CJK Windows locales#108967

Merged
steipete merged 8 commits into
openclaw:mainfrom
Yigtwxx:fix/windows-launcher-oem-codepage
Jul 17, 2026
Merged

fix: gateway.cmd launcher garbles non-ASCII profile paths on non-CJK Windows locales#108967
steipete merged 8 commits into
openclaw:mainfrom
Yigtwxx:fix/windows-launcher-oem-codepage

Conversation

@Yigtwxx

@Yigtwxx Yigtwxx commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Closes #108774

What Problem This Solves

Fixes an issue where Windows users whose profile path contains non-ASCII characters outside the CJK range (Turkish, Cyrillic, Greek, Western European accents, ...) can install OpenClaw but the managed Gateway never starts: the generated gateway.cmd launcher garbles the profile path and the launch chain dies with "The system cannot find the path specified" / MODULE_NOT_FOUND.

#107751 fixed this failure for CJK locales by encoding the launcher in the system ANSI code page — but only on locales where ANSI == OEM, and it deliberately left windows-125x hosts on plain UTF-8 ("ANSI bytes would just be a different flavor of wrong there"). On those hosts (e.g. Turkish: ANSI 1254, OEM 857) cmd.exe still reads the UTF-8 launcher in its OEM code page and the mojibake from #108774 persists.

Why This Change Was Made

cmd.exe parses batch files with the console code page, which a fresh console (Task Scheduler, Startup folder, double-click) initializes from the boot-time registry OEMCP — not from the ANSI page, and not from whatever a parent session last chcp'd to. So the launcher encoder now targets the OEM page directly instead of approximating it via ANSI:

  • resolveWindowsOemEncoding() (new, src/infra/windows-encoding.ts) reads HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP once (cached) through a narrow queryWindowsRegistryValue export that reuses the existing reg.exe query logic in src/infra/windows-install-roots.ts.
  • encodeWindowsLauncherScript (src/infra/windows-launcher-encoding.ts) encodes non-ASCII .cmd content to that OEM page with the same @rem openclaw-launcher-encoding=<label> marker and fail-closed round-trip verification introduced in fix(daemon): gateway fails to launch on Windows when the profile path contains CJK characters #107751. The CMD_ANSI_EQUALS_OEM_ENCODINGS special case is deleted: on CJK locales OEMCP == ACP, so those hosts resolve the identical labels (gbk/big5/shift_jis/euc-kr/windows-874) and produce byte-identical launchers — no behavior change there.
  • Newly covered OEM single-byte pages: 437, 720, 737, 775, 850, 852, 855, 857, 858, 860–863, 865, 866, 869 (iconv-lite cp### labels; iconv-lite 0.7.2 is already a root dependency since fix(daemon): gateway fails to launch on Windows when the profile path contains CJK characters #107751).
  • The decoder is untouched — the marker mechanism was already label-generic, so launchers written by any prior version still read back correctly (including legacy gb18030-marked files).

Design notes:

  • Why not %APPDATA%/%ProgramFiles% substitution (the issue's suggested fix): the ClawSweeper review on Bug: gateway.cmd breaks with non-ASCII Windows usernames (mojibake) #108774 correctly notes that would break custom npm prefixes, portable Node, and version managers. This fix keeps the installer-resolved paths and makes the encoding correct instead.
  • Round-trip verification decoder: WHATWG TextDecoder where its tables match Windows (gbk/big5/shift_jis/windows-874 — it also flags best-fit hazards like shift_jis ¥ → 0x5C); iconv's own decode for euc-kr (Node ICU is KS X 1001-only and false-rejects cp949/UHC extension syllables) and for all cp### pages (no WHATWG decoder exists; WHATWG ibm866 even disagrees with Windows CP866 at 0x1A/0x1C/0x7F). Safe because iconv-lite never best-fits — unmappable characters become ? and fail the round-trip, aborting the install with the existing clear error.
  • Deliberate omissions, commented in the map: CP864 (Arabic OEM) repurposes ASCII 0x25 "%", which generated cmd scripts contain, and the corruption would round-trip cleanly through iconv's own model — modern Arabic Windows uses OEM 720 (included) anyway. CP1258 (Vietnamese, the one locale whose OEMCP is a windows-125x page) is omitted because iconv-lite cannot round-trip Vietnamese combining forms; it keeps today's UTF-8 fallback instead of turning mojibake into a hard install error. Hosts with the "UTF-8 worldwide" beta (OEMCP 65001) keep plain UTF-8, which is correct there.

User Impact

openclaw gateway install + gateway start now works for Windows accounts with Turkish/Cyrillic/Greek/Western-European/etc. non-ASCII usernames — previously the P0 release-blocker path in #108774. CJK users see byte-identical output to #107751. ASCII-only installs are untouched (encoder still short-circuits before any code-page probe).

Evidence

Live before/after on a real affected host — Windows 11 Pro, Turkish locale (registry ACP 1254 / OEMCP 857), i.e. exactly the ANSI≠OEM case #107751 left open. A launcher with buildTaskScript-shaped content (cd /d, set "OPENCLAW_STATE_DIR=...", node invocation) pointing into a ...\ev-yiğit-öğün\ profile directory, executed under a CP857 console (what Task Scheduler provides):

Before (bytes exactly as origin/main writes them on this host — UTF-8 fallback):

Sistem belirtilen yolu bulamıyor.            <- cd /d failed ("The system cannot find the path specified")
Error: Cannot find module 'C:\...\ev-yi─şit-├Â─ş├╝n\probe.js'   <- UTF-8 bytes misread as CP857
exit code: 1

After (bytes from the fixed encodeWindowsLauncherScript(), real production function + real registry read, which resolved cp857 and emitted the @rem openclaw-launcher-encoding=cp857 marker):

PROBE_OK cwd=C:\...\scratchpad\ev-yiğit-öğün
PROBE_OK stateDir=C:\...\scratchpad\ev-yiğit-öğün\state
exit code: 0

Tests (all pass, node scripts/run-vitest.mjs ...): src/infra/windows-launcher-encoding.test.ts, src/infra/windows-encoding.test.ts, src/daemon/schtasks.test.ts, src/daemon/schtasks.install.test.ts, src/infra/windows-task-restart.test.ts — 49 tests. New regression cases: cp857 Turkish path round-trip with marker, cp850 Western European, OEMCP-65001 stays UTF-8, unrepresentable characters on a single-byte OEM page fail the install fail-closed. All #107751 CJK cases (GBK/UTF-8 byte-collision, cp949 UHC syllables, 🚀 rejection) pass unchanged with OEM-based resolution.

oxfmt and oxlint clean on all touched files; tsgo -p tsconfig.core.json reports no errors in touched files (the 42 pre-existing errors on this machine reproduce identically on a clean origin/main checkout — local env, unrelated).

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: M labels Jul 16, 2026
@Yigtwxx
Yigtwxx force-pushed the fix/windows-launcher-oem-codepage branch from 474a1b4 to 2a6c4a1 Compare July 16, 2026 12:46
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. labels Jul 16, 2026
@clawsweeper

clawsweeper Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 17, 2026, 3:08 AM ET / 07:08 UTC.

Summary
The PR detects the boot-time Windows OEM code page, writes .cmd launchers in a declared round-trip-safe encoding, rejects unsafe pages, and expands launcher, scheduled-task, and restart regression coverage.

PR surface: Source +95, Tests +202. Total +297 across 10 files.

Reproducibility: yes. The PR supplies a concrete current-main failure and successful after-fix run on a real Turkish Windows 11 host where ACP 1254 differs from OEMCP 857.

Review metrics: none identified.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #108774
Summary: This PR is the direct fix candidate for the canonical non-ASCII Windows launcher issue; the earlier merged CJK fix addressed the same encoding family only where ANSI and OEM code pages align.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P2] Unsupported, syntactically unsafe, or non-round-trippable OEM pages now stop launcher installation instead of retaining the previously broken UTF-8 fallback; this is an intentional compatibility and availability tradeoff.
  • [P1] The branch is behind current main and exact-head checks are still running, so it should be refreshed and revalidated before merge.

Maintainer options:

  1. Refresh and land with exact-head proof (recommended)
    Update the branch against current main and merge after the Windows and required exact-head checks confirm the OEM launcher behavior remains intact.
  2. Retain the old fallback
    Keep UTF-8 fallback on unsupported pages, accepting that affected non-UTF-8 consoles can continue generating launchers that install successfully but cannot start.

Next step before merge

  • No automated repair defect remains; refresh the behind base, let exact-head Windows and required checks complete, then perform normal maintainer landing review.

Security
Cleared: The diff changes local Windows encoding and registry-read logic without adding dependencies, workflow permissions, secret access, downloaded code, or a new external execution source.

Review details

Best possible solution:

Land the OEM-aware encoder with explicit chcp, generic marker-based readback, strict round-trip validation, and fail-closed handling for code pages that cannot safely represent generated batch syntax.

Do we have a high-confidence way to reproduce the issue?

Yes. The PR supplies a concrete current-main failure and successful after-fix run on a real Turkish Windows 11 host where ACP 1254 differs from OEMCP 857.

Is this the best way to solve the issue?

Yes. Encoding the installer-resolved paths for the console's actual OEM page preserves custom prefixes and portable Node layouts, while environment-variable substitution would create incorrect path assumptions.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against d78396124eb6.

Label changes

Label justifications:

  • P0: The reported defect leaves affected first-time Windows users with an installed but unusable Gateway and requires manual launcher editing to recover.
  • merge-risk: 🚨 compatibility: The patch deliberately replaces UTF-8 fallback with fail-closed installation for unsupported or unsafe OEM code pages.
  • merge-risk: 🚨 availability: Incorrect OEM detection or encoding could prevent the managed Gateway launcher from being written or started on affected Windows systems.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): A real affected Windows host demonstrates the current launcher failure and successful after-fix CP857 production path with exact cwd, state-directory, and exit-code output.
  • proof: sufficient: Contributor real behavior proof is sufficient. A real affected Windows host demonstrates the current launcher failure and successful after-fix CP857 production path with exact cwd, state-directory, and exit-code output.
Evidence reviewed

PR surface:

Source +95, Tests +202. Total +297 across 10 files.

View PR surface stats
Area Files Added Removed Net
Source 4 142 47 +95
Tests 6 242 40 +202
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 10 384 87 +297

What I checked:

Likely related people:

  • steipete: Assigned the PR and authored the current branch's OEM declaration, fail-closed guards, CP1258/CP864 handling, and final deterministic test updates. (role: recent area contributor and reviewer; confidence: high; commits: bf1594241ccb, 43ddecef2218, ffa158294137; files: src/infra/windows-encoding.ts, src/infra/windows-launcher-encoding.ts, src/infra/windows-launcher-encoding.test.ts)
  • wsyjh8: Authored the merged CJK launcher fix that introduced the current encoding marker, round-trip checks, launcher write integration, and the explicitly documented ANSI/OEM limitation this PR completes. (role: introduced current launcher-encoding behavior; confidence: high; commits: ccec0224fa2e; files: src/infra/windows-launcher-encoding.ts, src/infra/windows-launcher-encoding.test.ts, src/daemon/schtasks.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (7 earlier review cycles)
  • reviewed 2026-07-16T12:53:31.028Z sha 2a6c4a1 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-16T20:04:55.298Z sha 28b40b8 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-17T05:35:28.238Z sha 3c4aaf7 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-17T05:58:19.636Z sha df35a19 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-17T06:15:07.625Z sha 17291ed :: needs maintainer review before merge. :: none
  • reviewed 2026-07-17T06:24:43.633Z sha 537c810 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-17T06:57:15.487Z sha 1c0b82e :: needs maintainer review before merge. :: none

@Yigtwxx
Yigtwxx force-pushed the fix/windows-launcher-oem-codepage branch from 2a6c4a1 to 28b40b8 Compare July 16, 2026 19:59
@steipete steipete self-assigned this Jul 17, 2026
@steipete
steipete force-pushed the fix/windows-launcher-oem-codepage branch from 28b40b8 to 6502b2a Compare July 17, 2026 05:22
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 17, 2026
@steipete
steipete force-pushed the fix/windows-launcher-oem-codepage branch 5 times, most recently from 537c810 to 44b713b Compare July 17, 2026 06:34
@clawsweeper

clawsweeper Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix: gateway.cmd launcher garbles non-ASCII profile paths on non-CJK Windows locales This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@steipete
steipete force-pushed the fix/windows-launcher-oem-codepage branch 2 times, most recently from b6cefa9 to 1c0b82e Compare July 17, 2026 06:51
Yigtwxx and others added 6 commits July 17, 2026 08:03
The launcher encoder now resolves the boot-time OEM code page via
resolveWindowsOemEncoding, leaving resolveWindowsSystemEncoding with no
external importers; the dead-export ratchet (knip all-exports) fails CI
on exported-but-module-local functions.
@steipete
steipete force-pushed the fix/windows-launcher-oem-codepage branch from 1c0b82e to 400fb82 Compare July 17, 2026 07:03
@steipete

Copy link
Copy Markdown
Contributor

Maintainer proof for head 400fb825fbfec35c9abd2db008c86cb3678e8187:

  • Focused launcher/task suite: 149/149 passed with node scripts/run-vitest.mjs across Windows encoding, launcher encoding, scheduled-task install/startup, and restart coverage.
  • Full branch autoreview: clean; no accepted/actionable findings.
  • Native Windows CI: passed.
  • Turkish CP857 live proof: passed. Gateway install/start/status reached running; launcher path round-trip and active UTF-8 console override checks both passed.
  • Exact-head PR CI: 83 success, 35 skipped, 1 neutral; no failures or pending checks. Transient OpenGrep download and 0.6 MB startup-memory variance passed on rerun.

Review artifacts validated with recommendation READY FOR /prepare-pr.

@steipete
steipete merged commit e228a3c into openclaw:main Jul 17, 2026
188 of 191 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

@Yigtwxx
Yigtwxx deleted the fix/windows-launcher-oem-codepage branch July 17, 2026 18:24
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 18, 2026
…Windows locales (openclaw#108967)

* fix(daemon): encode Windows cmd launcher to the console OEM code page

* fix(infra): unexport resolveWindowsSystemEncoding

The launcher encoder now resolves the boot-time OEM code page via
resolveWindowsOemEncoding, leaving resolveWindowsSystemEncoding with no
external importers; the dead-export ratchet (knip all-exports) fails CI
on exported-but-module-local functions.

* test(windows): cover OEM launcher encoding resolver

* fix(windows): declare launcher OEM code page

* fix(windows): fail closed on unsupported OEM pages

* fix(windows): reject CP1258 precomposition drift

* fix(windows): guard CP864 launcher syntax

* test(windows): pin OEM launcher code page

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: gateway.cmd breaks with non-ASCII Windows usernames (mojibake)

2 participants