Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Bug] Dashboard self-update loses worker under custom systemd system service

Open
#7,967 4 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
28/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
linux, node.js, typescript
Domain
backend, devops

Research direction

Start by locating the Dashboard npm update worker, its service ownership detection and restart logic, and the job status handling; the issue does not name source files or tests. Read the v2.93.0 baseline and the staging candidate's synthetic tests, then trace how the actual systemd owner and worker scope are verified. Done means the updater safely refuses unsupported custom system units before package mutation, preserves or reports failure for the job, and has coverage for the stated lifecycle cases; destructive end-to-end certification is still outstanding.

Written by the indexing model from the issue text.

Description

bug gui proxy service
Client or integration

OpenCodex dashboard

Area

Service lifecycle

Summary

A Dashboard-triggered npm self-update can leave OpenCodex unavailable (HTTP 502 from the reverse proxy) on Linux when the running proxy belongs to a system-wide systemd service under an unprivileged UID, rather than the canonical systemd user service. An update worker may die when the original service's cgroup is stopped; moreover the updater may target a different, installed-but-inactive user unit. The Dashboard job file can remain running with a dead worker PID.

Expected: never stop an active proxy unless a worker can outlive the stop and can restart the actual owner. Unsupported custom system units should receive an actionable, fail-closed error before package mutation.

Reproduction
  1. Configure a custom root-owned systemd service with User=<unprivileged-user>, KillMode=control-group, OCX_SERVICE_MANAGED=1, and ExecStart=ocx start --port 10101. Keep an OpenCodex-managed systemctl --user service installed but inactive.
  2. With OpenCodex v2.89.0 running under the system unit, start a v2.93.0 npm update with restart:true from the Dashboard.
  3. During stop/restart, the original proxy disappears and the browser reports 502; the update job can remain running even though its recorded PID is dead.
  4. Non-destructive supporting reproduction under the same UID: systemd-run --user --scope --quiet --collect -- /usr/bin/true fails with Failed to connect to bus: No medium found when the system service has INVOCATION_ID but no XDG_RUNTIME_DIR. Supplying the verified private /run/user/<uid> makes the scope probe exit 0. A test process launched in that scope is shown under /user.slice/.../app.slice/run-*.scope, outside the system unit cgroup.
  5. Distinct installed supervisor state was reproduced: ocx service status --json reports the user unit installed/enabled but running:false, viable:false, while the independent system unit serves HTTP 200.

The full destructive update scenario has not been re-enacted after remediation; do not treat the non-destructive probes alone as a completed E2E certification.

Version

OpenCodex 2.89.0 → 2.93.0; source baseline v2.93.0 commit 88aaa754566d119b6b8fc898f8fb47602387d82e.

Operating system

Linux, systemd system service + lingered systemd user manager, Bun 1.4.4.

Provider and model

Not provider-specific.

Logs or error output
Failed to connect to bus: No medium found
OWNERSHIP_MUTATION_LEASE_BUSY: another process owns the runtime mutation lease
(recorded PID no longer alive; lease age below stale-reclaim grace period)
systemd: Main process exited, status=1/FAILURE
systemd: Failed to start OpenCodex proxy service
Screenshots and supporting files

The operator captured HTTP 502 Bad gateway during the Dashboard upgrade and a separate startup-safety warning. No screenshots containing private hostnames or identifiers are uploaded here.

Redacted configuration
{
  "systemService": {
    "type": "systemd system",
    "user": "<unprivileged uid>",
    "killMode": "control-group",
    "managed": true
  },
  "dashboardUpdate": {
    "installer": "npm",
    "restart": true
  },
  "userService": {
    "installed": true,
    "enabled": true,
    "running": false
  }
}
Checks
  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.
Suggested safety contract
  • Identify and attest the actual running supervisor before beginning update.
  • Spawn the updater in an independently managed scope with a verified UID-private user-bus socket. Refuse safely if that is impossible.
  • Do not target an unrelated user unit when a root-owned custom system unit owns the listener; such a migration needs operator-supervised authorization.
  • Record a terminal, actionable failed state when the updater PID died; avoid indefinite running status.
  • Test service stop, update, restart identity, health stability, rollback and cgroup survival.

A staging-only candidate adds these guards with synthetic tests; it is not deployed or certified.

Dominant language
TypeScript
Stars
16.9k
Forks
1.3k
Avg merge
16h 25m
Merged PRs (30d)
706

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from lidge-jun/opencodex

All issues in lidge-jun/opencodex

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.