Skip to content

[Bug]: Elevated Task Scheduler re-registration exceeds command-line limit — ENAMETOOLONG (uv_spawn) with double base64 XML payloads #4692

Description

@mustardwheat

Summary

When ocx service repair re-registers the Task Scheduler task through the elevated fallback, the spawn fails with:

WindowsElevationError: ENAMETOOLONG: name too long, uv_spawn
    at startPowerShellCommand (…/src/lib/windows-elevation.ts:560)
    at runWindowsElevatedScheduledTaskRegistration (…/src/lib/windows-elevation.ts:704)
    at registerFreshWindowsSchedulerTask (…/src/service/windows-ops.ts:313)
    at reregisterWindowsSchedulerTask (…/src/service/windows-ops.ts:430)
    at repairService (…/src/service/repair.ts:212)

runWindowsElevatedScheduledTaskRegistration embeds two full XML payloads — the new task XML and the expected-existing snapshot (replace precondition) — as base64(utf16le) inside an inner PowerShell script, which is then itself base64(utf16le)-encoded into the outer -EncodedCommand. With a ~2 KB task XML this pushes the outer command line past the Windows spawn limit. Observed on 2.54.0; the snapshot precondition added the second payload, and the same code is present in 2.55.0.

Two aggravating factors on affected hosts:

Environment

  • OS: Windows 11, zh-CN
  • opencodex 2.54.0 (same code in 2.55.0)

Reproduction

  1. Register opencodex-proxy from an elevated installer (task file owned by Administrators).
  2. Use an account whose session-trigger scope exports as an account name rather than the SID (a CJK account name works, per [Bug]: decodeSchtasksOutput UTF-8 fallback mangles GBK schtasks output on zh-CN Windows — service repair/install fails with CJK account name #4691) so identityUpgradeNeeded stays true.
  3. ocx service repair → non-elevated schtasks /create /f returns Access is denied → elevated fallback → ENAMETOOLONG: name too long, uv_spawn.

Suggested fix

Pass the XML through an ACL-protected staging file (readable only by the elevated process) and reference its path in the elevated command — or write the inner script to a temp .ps1 — instead of double-base64 inline payloads. The current "immutable bytes, never a caller-writable pathname" design goal can be preserved by ACL-hardening the staged file (similar to hardenSecretPath).

Workaround that unblocked us: delete the admin-owned task once from an elevated prompt (schtasks /delete /tn opencodex-proxy /f), then let repair re-create it as the current user; afterwards the non-elevated replace succeeds and the elevated path is never needed.

  • I searched existing issues and documentation (no prior ENAMETOOLONG report found).
  • I removed secrets, tokens, account details, request credentials, and personal data.

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