Skip to content

[Bug]: decodeSchtasksOutput UTF-8 fallback mangles GBK schtasks output on zh-CN Windows — service repair/install fails with CJK account name #4691

Description

@mustardwheat

Summary

On a zh-CN Windows host (OEMCP/ACP 936), ocx service repair — and the Dashboard repair/install buttons — fail against a registration that OpenCodex itself created:

Service repair failed: Task Scheduler registration is not a recognized legacy OpenCodex definition; it was preserved for manual review.

Root cause: redirected schtasks /query /xml output follows the console output code page of the spawning process tree, not the XML document encoding. In any 936 console context (including the no-console background service on a zh-CN host), the bytes are GBK. decodeSchtasksOutput (src/service/windows-scheduler.ts, moved from src/service.ts in the 2.54 refactor) probes UTF-16 and then falls back to a plain UTF-8 decode, which turns the CJK account name inside <SessionStateChangeTrigger><UserId> into U+FFFD replacement characters. The correctly resolved expected identity [SID, MACHINE\user] then never matches the trigger scope, windowsTaskRegistrationHealthy() returns false, and repair aborts at the recognition gate. The same mojibake also rolls back fresh installs at the post-create verification ("...registration was created but failed the OpenCodex action/trigger or attempt-ownership verification. The invalid registration was rolled back.").

This is the remaining unwired call site of the decoder the project already built for exactly this class: decodeWindowsTextBytes (src/lib/windows-text.ts, UTF-16 → strict UTF-8 → locale legacy page incl. GBK) already fixed the sibling whoami/PowerShell decode in src/lib/windows-user-principal.ts (#2914, and #722 for CP949). Related: #3064 (non-ASCII profile path), #4106 (closed as not-planned; that reporter's console was CP 65001 — a different manifestation. The failure below reproduces deterministically under any 936 console).

Environment

  • OS: Windows 11, system locale zh-CN (ACP=936, OEMCP=936)
  • Local account name contains CJK characters
  • opencodex: observed on 2.47.0 → 2.55.0; dev branch fetched 2026-09-08 still has the same fallback

Reproduction

  1. ocx service install on a zh-CN host with a CJK account name. The task registers with SID-scoped session triggers; Task Scheduler export canonicalizes the SID back to the CJK account name.
  2. From a console with chcp 936 (or via the Dashboard, whose repair child runs without a console under the 936 service context), run ocx service repair.
  3. Observe the recognition error above (exit code 1; the subsequent serving check still prints the "repaired and serving" line because the proxy was never stopped).

Instrumented A/B against the real repairService (2.54.0, chcp 936):

  • statusWindowsXml() returns trigger scopes as MACHINE\???? (U+FFFD); resolveWindowsTaskDiagnosticUserId() returns the correct [SID, MACHINE\<CJK-name>]; windowsTaskRegistrationHealthy() → false → gate throws.
  • Same bytes through decodeWindowsTextBytes → correct account name; healthy → true; ocx service repair exits 0.

Suggested fix

One-line delegation plus import (running locally as a hotfix since 2.47.0; every npm i -g overwrite brings the bug back):

import { decodeWindowsTextBytes } from "../lib/windows-text";

export function decodeSchtasksOutput(buffer: Buffer): string {
  return decodeWindowsTextBytes(buffer);
}

Logs

❌ Service repair failed: Task Scheduler registration is not a recognized legacy OpenCodex definition; it was preserved for manual review.
✅ opencodex service repaired and serving on port 10100.   (serving check still passes; exit code is 1)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglanded-via-maintainerOriginal PR closed after landing via a maintainer merge trainplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)serviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions