Skip to content

[Bug][Windows] Auto-update leaves proxy dead after npm EPERM on bun binary replacement #281

Description

@Wibias

Summary

When the auto-update flow runs (ocx update) on Windows, npm cannot fully clean up the old bundled bun binary because bunx.exe is still locked by a running process. The bun postinstall script is also blocked. After the update, the port-availability check times out and the proxy restart is unreliable.

Note on the "proxy dies silently after restart" claim: Further investigation showed that the post-update proxy (PID 5176 in the original report, uptime ~12s) did not crash -- a monitoring script with a too-short healthz timeout mistakenly killed it. The EPERM cleanup failure and blocked postinstall are still real issues worth fixing independently.

Steps to reproduce

  1. Have the proxy running on Windows
  2. Trigger an update (via UI or ocx update)
  3. The update stops the old proxy, runs npm install -g @bitkyc08/opencodex@latest
  4. npm fails to clean up the old bun binary with EPERM: operation not permitted, unlink 'bunx.exe'
  5. npm's bun postinstall script is also blocked (bun@1.3.14 postinstall: node install.js not run due to allow-scripts)
  6. The update flow logs "Port 10100 still busy after stop" and starts the proxy anyway

Evidence from update-job.json

"npm warn cleanup Failed to remove some directories"
"npm warn cleanup   'C:\\...\\@bitkyc08\\.opencodex-1JejBqbZ\\node_modules\\bun\\bin\\bunx.exe'"
"npm warn cleanup     [Error: EPERM: operation not permitted, unlink ...]"
"npm warn install-scripts bun@1.3.14 (postinstall: node install.js) blocked"
"Port 10100 still busy after stop; starting with --port 10100 anyway."

The orphaned temp directory .opencodex-1JejBqbZ containing the old bunx.exe is left behind and persists across reboots.

Why it happens

On Windows, a running executable cannot be deleted or replaced while it is in use. The update flow stops the proxy (killing the main bun.exe process), but something -- possibly a lingering node/npm subprocess or a file handle from the previous session -- still holds bunx.exe open. npm therefore cannot complete its cleanup, the postinstall script for bun is skipped, and orphaned temp dirs accumulate in node_modules/@bitkyc08/.

Impact

  • Every auto-update on Windows leaves orphaned temp dirs in node_modules/@bitkyc08/
  • The bun postinstall script is never run, so every npm-based update is technically incomplete
  • The port-availability wait races against Windows' TCP drain, occasionally causing the restart to fail
  • No user-visible error beyond the npm warn lines buried in update-job.json

Suggested fix

  1. After npm install, attempt cleanup of orphaned .opencodex-* temp dirs in the node_modules/@bitkyc08/ directory -- these are safe to delete after install completes since the old binary is no longer needed.
  2. Extend the port-availability wait or retry before logging the "still busy" warning, giving Windows more time to drain the TCP socket after taskkill.

Environment

  • OS: Windows 11, PowerShell
  • Node: v24.15.0 (via nvm)
  • Installer: npm global
  • Updated from: 2.7.31 to 2.7.33
  • OpenCodex version: 2.7.33

Activity

  1. Ingwannu commented on Jul 22, 2026

    @Ingwannu
    Owner

    Reproduced statically against current origin/dev (56b75eb7).

    The updater log line from your report — Port 10100 still busy after stop; starting with --port 10100 anyway. — only exists in src/update/job.ts, i.e. the GUI/dashboard update worker path that writes update-job.json. In that same file the worker currently does:

    • await restartAfterUpdate(job, captured);
    • then immediately marks the job succeeded with Restart requested.

    So the root cause is real: a detached replacement proxy can die a few seconds later on Windows, but the job still reports success because there is no post-restart health/stability confirmation.

    I opened a draft fix here: #284

    What the patch does:

    • waits for an identity-checked /healthz after restart
    • requires the restarted proxy to stay healthy for a short stability window before marking success
    • fails update-job.json with an actionable Windows recovery hint when the replacement proxy never comes up or flaps
    • adds updater regression tests for the new failure lanes

    Validation on the branch:

    • bun test tests/update-job.test.ts
    • bun run typecheck
    • bun run privacy:scan

    Keeping this issue open until the draft PR is reviewed/merged.

  2. Ingwannu commented on Jul 22, 2026

    @Ingwannu
    Owner

    Fixed and merged into dev via PR #284. The updater now verifies the restarted OpenCodex service identity before marking success; a dead/foreign/unstable proxy records failure with a Windows recovery hint instead of a false success. Full tests and cross-platform CI passed; closing as completed.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions