coleam00/Archon · error
Detached run control endpoint is already owned: ${path}
Error message
Detached run control endpoint is already owned: ${path} What it means
When starting the detached-run control Unix socket server, if listen() fails with EADDRINUSE on POSIX the code checks whether the existing endpoint is connectable. A successful connection proves another live process already owns this run's control endpoint, so it throws instead of stealing the socket. Only a refused connection (crashed owner) allows removing the stale socket path and rebinding.
Source
Thrown at packages/cli/src/utils/detached-run-control.ts:152
});
}
function isNodeError(error: unknown): error is NodeJS.ErrnoException {
return error instanceof Error;
}
async function listenWithoutReplacingOwner(server: Server, path: string): Promise<void> {
try {
await listen(server, path);
return;
} catch (error) {
if (!isNodeError(error) || error.code !== 'EADDRINUSE' || process.platform === 'win32') {
throw error;
}
}
if (await canConnect(path)) {
throw new Error(`Detached run control endpoint is already owned: ${path}`);
}
// A crashed Unix owner can leave the socket pathname behind. Connection refusal,
// not age, is the proof that no process owns it; remove only that stale pathname.
rmSync(path, { force: true });
await listen(server, path);
}
async function acquireOwnerLock(runId: string, endpointPath: string): Promise<number> {
const lockPath = detachedRunControlLockPath(runId);
try {
return openSync(lockPath, 'wx', 0o600);
} catch (error) {
if (!isNodeError(error) || error.code !== 'EEXIST') throw error;
}
if (await canConnect(endpointPath)) {
throw new Error(`Detached run control endpoint is already owned: ${endpointPath}`);View on GitHub (pinned to 0773b97458)
Solutions
- Confirm the existing owner is alive and use it: query the run's status instead of starting a new control server.
- If you intended a new owner, first cancel/stop the existing owner process, then restart.
- Verify you are not starting the same run id twice (check your wrapper scripts or CI for duplicate launches).
Example fix
// before archon run resume <runId> # second instance -> endpoint already owned // after archon run stop <runId> # terminate current owner archon run resume <runId>
Defensive patterns
Strategy: retry
Validate before calling
// Before starting, test if an owner already answers:
const alive = await canConnect(socketPath); // your own helper
if (alive) console.log('Run already owned; attach/stop instead of starting.'); Try / catch
try {
await startDetachedRunControlServer(...);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Detached run control endpoint is already owned')) {
// fall back to attaching/querying the existing owner
const pid = await getDetachedRunOwnerPid(runId);
} else throw err;
} Prevention
- Serialize all start/attach commands for a given run id.
- Check run state via CLI before starting a second owner.
- Detect the 'already owned' message in scripts and switch to attach mode.
When it happens
Trigger: startDetachedRunControlServer is called while another live Archon process holds the control socket for the same run id, and canConnect(path) succeeds.
Common situations: Two instances of the same detached run started concurrently; trying to resume/control a run from a second terminal while the original owner process is still alive; a run id reused while the old owner is running.
Related errors
- Detached run control endpoint is already owned: ${endpointPa
- owner returned an invalid response
- owner returned an invalid PID
- Refusing detached run control because process ${String(proce
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/c269a61b17140e2a.
Report an issue: GitHub.