Repository navigation
[Bug]: mise upgrades can strand systemd on removed versioned OpenCodex paths #2898
Description
Client or integration
Codex CLI
Area
Service lifecycle
Summary
The Linux systemd user unit generated by ocx service install embeds the absolute, versioned OpenCodex CLI and bundled Bun paths. When OpenCodex is installed through mise, mise upgrade opencodex installs the next release under a different version directory without running OpenCodex's own update workflow, so the installed unit remains tied to the previous version.
Once mise removes the previous install or the service is restarted after pruning, systemd has no executable at the baked path and the background proxy cannot start. ocx service repair fixes the unit, but it has to be run manually after every external package-manager upgrade.
I currently need this mise configuration as a local workaround:
opencodex = { version = "latest", postinstall = 'if test -f "$HOME/.config/systemd/user/opencodex-proxy.service"; then "$MISE_TOOL_INSTALL_PATH/node_modules/.bin/ocx" service repair; fi' }The guard makes a first installation without a service a no-op and forces an existing service to be re-baked after mise changes the install path.
Expected: an installed OpenCodex service remains startable across supported external package-manager upgrades, or OpenCodex provides a package-manager-independent launcher/service path that does not require a per-manager postinstall repair hook.
Actual: the service definition is coupled to one mise version directory and becomes stale when that directory is replaced or pruned.
Reproduction
-
Install OpenCodex through mise:
mise use -g opencodex@latest
-
Install the Linux user service:
ocx service install
-
Inspect the generated unit:
systemctl --user cat opencodex-proxy.service | grep -E '^(ExecStart|Environment="OCX_BUN_RUNTIME_PATH)='
Both the bundled Bun runtime and CLI entry point are under a version-specific path such as:
/home/<user>/.local/share/mise/installs/opencodex/2.35.0/... -
Upgrade to the next OpenCodex release through mise:
mise upgrade opencodex
-
Confirm the unit still names the previous version directory. After that old install is removed or pruned, restart the user service or reboot:
systemctl --user restart opencodex-proxy.service ocx status
-
Repairing manually re-bakes the unit and restores service health:
ocx service repair ocx status
This is distinct from #2411 and #2412. Their released fixes improve routing visibility and correctly reject a version-manager-owned Codex shim, but they do not make the OpenCodex systemd service survive an external OpenCodex package upgrade.
Version
2.35.0
Operating system
Ubuntu 24.04.4 LTS on WSL2, kernel 6.18.33.2-microsoft-standard-WSL2
Provider and model
Not provider- or model-specific.
Logs or error output
$ systemctl --user show opencodex-proxy.service -p ActiveState -p UnitFileState
ActiveState=active
UnitFileState=enabled
$ systemctl --user cat opencodex-proxy.service
# ExecStart and OCX_BUN_RUNTIME_PATH both contain:
/home/<user>/.local/share/mise/installs/opencodex/2.35.0/...Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Aug 29, 2026
리뷰 · 우선순위 62 / 80
설명
Linux에서
ocx service install이 만든 systemd user 유닛이 버전 경로가 박힌 CLI/Bun ExecStart를 쓰고, mise로mise upgrade opencodex하면 설치 디렉터리가 바뀌는데 유닛은 예전 경로를 남는다는 버그입니다. 이전 버전이 지워지거나 재시작되면 systemd가 실행 파일을 못 찾아 백그라운드 프록시가 안 뜹니다.ocx service repair로 다시 구우면 고치지만, 외부 패키지 매니저 업그레이드마다 수동 실행이 필요합니다.현재
dev에는 이미 stale 감지 문구가 있습니다.src/service.ts근처의STALE baked paths (missing: ...) — run 'ocx service repair' to re-bake(약 2513행)와#2869로 올라온 systemd 219 호환 정리,#2861의 staleProcessState 표면화가 같은 가족입니다. 다만 보고된 구멍은 "이미 죽었을 때 진단"이 아니라, mise처럼 OpenCodex 업데이트 워크플로를 거치지 않는 외부 업그레이드 후 자동으로 repair가 안 도는 것입니다. 작성자의 misepostinstall워크어라운드가 그 갭을 정확히 보여 줍니다.기대 동작은 (1) 버전드 절대경로 대신 안정적인 shim/wrapper를 ExecStart에 쓰거나, (2) 업그레이드/시작 시 베이크된 경로가 사라졌으면 자동 repair, (3) 최소한 doctor/status가 mise/외부 업그레이드 시나리오를 명시하는 것입니다.
src/update/index.ts는 자체 업데이트 경로에서ocx service repair를 안내하지만, mise postinstall은 그 경로를 타지 않습니다.이 문제는 Windows tray/scheduler 계열(#2856/#2857)과는 플랫폼이 다르고, types/config 분할과도 무관합니다. 서비스 수명주기 버그로
dev에 독립 착륙시키기 좋은 후보입니다. 우선순위는 "프록시가 안 떠서 전체가 멈춤"이라 체감이 큽니다.경로 src/service.ts ExecStart 생성 - 절대 버전 경로를 굽는 설계가 mise/nix/asdf 같은 버전드 prefix와 충돌합니다. shim(
~/.local/bin/ocx)이나$MISE_TOOL_INSTALL_PATH가 아닌 안정 링크를 쓸지 설계가 필요합니다.경로 STALE baked paths 진단 - 이미 탐지는 있지만, 실패 시점이 서비스 start 이후라 사용자가 먼저 장애를 겪습니다. install/ensure/start 초기에 경로 existence 검사 후 자동 repair 후보입니다.
경로 src/update - 자체 업데이트만 repair를 안내하고 외부 패키지 매니저는 비어 있습니다. 문서에 mise postinstall 예시를 공식화할지, 코드로 훅을 넣을지 결정이 필요합니다.
심볼 ocx service repair - 해결책은 이미 있는데 트리거가 수동입니다. "도구 없음"이 아니라 "자동화 구멍"입니다.
메인테이너의 판단이 필요한 지점
ocx ensure/ocx start가 stale baked path면 자동 repair를 돌릴지(부작용: 의도치 않은 유닛 재작성)너의 추천
버그 라벨 유지하고 받아 두세요. 추천 방향은 (A) ExecStart를 가능한 한 안정적인
ocxshim으로 재베이크 + (B) start/ensure 시 missing baked binary면 repair 제안 또는 자동 repair입니다. 문서에 작성자 mise postinstall 예시를 당분간 공식 워크어라운드로 적어도 좋습니다. 닫지 마세요.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Aug 29, 2026
Fixed on
devin 4ec1cc9 (#2909).Your diagnosis was right, and the mechanism is worth stating precisely because it explains
why the service looked installed the whole time. Both paths baked into the unit — the bundled
Bun and the CLI entry — are derived from
import.meta.dir, so both live inside the versionedinstall directory. Once mise removes it,
/bin/shstill starts,exec <old-bun> <old-cli>fails, and
Restart=on-failurerestart-loops.startSystemdonly checked unit existence anddaemon-reload state, so nothing on the start path noticed.
The unit now invokes the stable
ocxexecutable resolved fromPATHat install time. A miseor asdf shim survives the upgrade and dispatches to whatever version is current. Two details
that mattered:
realpathon the shim would write the versionedtarget straight back into the unit and recreate the bug — the indirection is the point.
ExecStartnever re-resolves a bareocxthroughPATHon each restart.OCX_BUN_RUNTIME_PATHis also dropped in launcher mode, since stamping it would pin theruntime to the same directory the upgrade deletes. Source checkouts without an
ocxlauncherkeep the previous direct Bun + CLI form.
A second half was needed that the report did not mention: the install state now records the
launcher, and the staleness diagnostic judges against it. Without that, a perfectly healthy
service reports
STALE baked pathsafter every upgrade, because the recorded Bun/CLI pairpoints into the replaced directory.
One action needed for existing installs. A unit written before this release still carries
the old versioned paths and cannot migrate itself — once the old executable is deleted there
is no OpenCodex code left running to fix it. Run
ocx service repaironce after upgrading;version changes after that need nothing.
Worth noting about verification: no live systemd host was exercised. The regression tests
build a real shim, point it at v1, retarget it to v2, delete v1, and execute the generated
command — but that is a shell-level proof, not a running systemd unit. If you can confirm on
your WSL setup after the next release, that would close the loop.