Repository navigation
Windows: ocx service install rolls back with a non-ASCII profile path #3064
Description
Client or integration
Codex CLI
Area
Service lifecycle
Summary
On Windows, a fresh ocx service install can create the opencodex-proxy Scheduled Task, then reject it as unhealthy and roll it back when the Windows user-profile path contains non-ASCII characters.
Expected: the valid task passes post-create verification and remains registered.
Actual: the install command rolls back the new task.
Reproduction
- Use a Windows account whose profile directory name contains non-ASCII characters.
- Install OpenCodex globally with
npm install -g @bitkyc08/opencodex. - Run
ocx service install. - Observe that
opencodex-proxyis created and then rolled back.
Diagnostic result: querying the task with schtasks /query /tn opencodex-proxy /xml returns the expected launcher path when its native output bytes are decoded directly. In contrast, the runFile() path used by src/service.ts supplies text that has already undergone code-page conversion, corrupting the non-ASCII part of <Arguments>. The subsequent task-registration health comparison fails.
A narrowly scoped code change that resolves the issue is to use Bun.spawnSync({ cmd: [windowsSchtasks(), ...args] }) only for /xml task queries, then pass Buffer.from(result.stdout) to decodeSchtasksOutput(); retain the existing runFile() fallback for all other queries.
Version
2.37.0
Operating system
Windows 11 24H2 (x64)
Provider and model
Not applicable; this occurs before any provider request.
Logs or error output
ocx service install
Service install cleanup failed: Task Scheduler registration was created but failed the OpenCodex action/trigger or attempt-ownership verification. The invalid registration was rolled back.The exact local profile path has been intentionally redacted.
Screenshots and supporting files
None.
Redacted configuration
No provider or routing configuration is required to reproduce. This is a default global npm installation followed by ocx service install.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Aug 31, 2026
리뷰 · 우선순위 68 / 80
이 이슈는 Windows에서 사용자 프로필 경로에 비ASCII(한글·일본어 등)가 있을 때
ocx service install이 Task Scheduler 작업opencodex-proxy를 만든 뒤, 사후 검증에서 unhealthy로 보고 롤백한다는 보고입니다. 기대는 방금 만든 유효한 등록이 그대로 남는 것이고, 실제는 "created but failed … verification. The invalid registration was rolled back."로 사라집니다. 보고 버전은 2.37.0, OS는 Windows 11 24H2입니다. 지금devHEAD는f83368dfd(패키지 2.38.0)이고, 관련 코드는 여전히src/service.ts한곳에 모여 있습니다.HEAD를 보면 이미 UTF-16 schtasks 출력 대응이 들어가 있습니다.
decodeSchtasksOutput(대략 865행 근처)는 BOM/짝수 null 패턴으로 UTF-16LE를 고르고,runFile(888행 근처)는execFileSync(..., { encoding: "buffer" })로 받은 버퍼를 그 디코더에 넘깁니다.querySchtasks(["/query", "/tn", ..., "/xml"])→verifyWindowsSchedulerInstall(1135행 근처) →windowsTaskRegistrationHealthy(2038행 근처)가Arguments안의 런처 경로를taskXmlDecodedValueEquals로 비교합니다. #2918이 CJK schtasks 디코드와 목록 완주를 고친 이력도 있습니다. 그런데도 이 보고는 "수동으로 받은 원본 바이트를 직접 디코드하면 경로가 맞고,runFile경로로 온 텍스트는 코드 페이지 변환이 이미 섞여<Arguments>가 깨진다"고 짚습니다. 즉 HEAD의 buffer+UTF-16 가드가 있어도, Windows에서execFileSync가 콘솔 코드 페이지로 한 번 지난 바이트를 주면 디코더가 UTF-8/UTF-16 어느 쪽으로도 복구하지 못한다는 가설입니다. 제안 수정은/xml쿼리만Bun.spawnSync({ cmd: [windowsSchtasks(), ...] })로 바꿔Buffer.from(result.stdout)를decodeSchtasksOutput에 넘기고, 나머지 쿼리는 기존runFile을 유지하는 좁은 변경입니다.라인 -
src/service.tsrunFile/querySchtasks:/xml일 때 spawn 경로를 타는지 여부가 이 버그의 핵심. 목록·CSV·create/delete는 기존 경로 유지가 맞음.라인 -
windowsTaskRegistrationBaseHealthy의Arguments비교(/b /nologo "…launcher…"): 런처가%USERPROFILE%아래 비ASCII면, XML 디코드가 깨지는 순간 unhealthy → 롤백으로 이어짐. 증상과 일치.라인 -
verifyWindowsSchedulerInstall의 디스크 XML 폴백(1137행 근처): 쿼리가 빈 문자열일 때만 디스크 문서를 씀. 쿼리가 모지바케 문자열을 성공적으로 반환하면 폴백이 안 타서, 깨진 비교가 그대로 실패함. spawn 수정이 우선이고, 필요하면 "쿼리 성공이지만 Arguments 불일치 + 디스크 XML은 healthy"일 때 디스크를 신뢰할지 별도 판단.라인 - 테스트: Linux CI만으로는 재현 불가.
decodeSchtasksOutput에 코드 페이지로 이미 깨진 바이트 픽스처를 넣어도 spawn vs execFileSync 차이를 증명하진 못함. Windows 실기기 또는 모의queryXmldeps로 회귀를 잠글 것.메인테이너의 판단이 필요한 지점
Bun.spawnSync만/xml에 쓸지,runFile전체를 Bun으로 통일할지. 후자는 면적이 커짐.너의 추천
도움 환영 이슈로 두고, 재현 확인 후
/xml전용Bun.spawnSync→decodeSchtasksOutput패치를 받는 쪽이 맞다. PR은src/service.ts와 Windows 단위/시나리오 테스트만. types/config 스플릿과 무관. 이미 #2918 계열이 있으면 "continues #2918"로 적고, 디스크 폴백 확장은 기본 패치에 넣지 말고 재현 로그 보고 결정하라.이 댓글은 grok-bot이 작성했습니다
fix(service): verify a scheduler path the console code page cannot carry
fix(service): verify a scheduler path the console code page cannot carry
fix(service): verify a scheduler path the console code page cannot carry
fix(service): forgive only what the code page mangled in a scheduler …
fix(service): Windows cold-start budget and code-page-mangled schedul…
lidge-jun commentedon Sep 1, 2026
Fixed on
devbyb14b741dc(#3134, rebase carry of #3104).schtasks /query /xmlconverts its output through the console code page before the bytes exist, so reading the stream as a buffer cannot recover them — a profile named outside that page comes back asC:\Users\???\..., and the exact string comparison then rejected a registration this very process had just created correctly. That rejection is what rolled the install back.The comparison now tolerates the mangling, but narrowly: each unrepresentable run in the expected value may match only a run of substitution characters — never arbitrary text, and never a path separator (
src/service.ts:2011-2013).The narrowness is the point. A wildcard as wide as
[^\\/]*forbids a separator but allows arbitrary ASCII, so a wholly non-ASCII segment would lose every anchor andC:\Users\<CJK>\.opencodex\service-launcher.vbswould matchC:\Users\Admin\.opencodex\service-launcher.vbs— this process could then adopt, repair, or delete another account's scheduled task.<UserId>had the same hole and is now handled by exact SID matching instead.Closing manually: PRs here target
dev, so GitHub's auto-close onCloses #does not fire.github-actions commentedon Sep 1, 2026
Automated translation bookkeeping — detected language: English.
fix(service): Windows cold-start budget and code-page-mangled schedul…
fix(service): Windows cold-start budget and code-page-mangled schedul…