{"record":{"id":"c269a61b17140e2a","repo":"coleam00/Archon","slug":"detached-run-control-endpoint-is-already-owned","errorCode":null,"errorMessage":"Detached run control endpoint is already owned: ${path}","messagePattern":"Detached run control endpoint is already owned: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/utils/detached-run-control.ts","lineNumber":152,"sourceCode":"  });\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n  return error instanceof Error;\n}\n\nasync function listenWithoutReplacingOwner(server: Server, path: string): Promise<void> {\n  try {\n    await listen(server, path);\n    return;\n  } catch (error) {\n    if (!isNodeError(error) || error.code !== 'EADDRINUSE' || process.platform === 'win32') {\n      throw error;\n    }\n  }\n\n  if (await canConnect(path)) {\n    throw new Error(`Detached run control endpoint is already owned: ${path}`);\n  }\n\n  // A crashed Unix owner can leave the socket pathname behind. Connection refusal,\n  // not age, is the proof that no process owns it; remove only that stale pathname.\n  rmSync(path, { force: true });\n  await listen(server, path);\n}\n\nasync function acquireOwnerLock(runId: string, endpointPath: string): Promise<number> {\n  const lockPath = detachedRunControlLockPath(runId);\n  try {\n    return openSync(lockPath, 'wx', 0o600);\n  } catch (error) {\n    if (!isNodeError(error) || error.code !== 'EEXIST') throw error;\n  }\n\n  if (await canConnect(endpointPath)) {\n    throw new Error(`Detached run control endpoint is already owned: ${endpointPath}`);","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/cli/src/utils/detached-run-control.ts#L134-L170","documentation":"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.","triggerScenarios":"startDetachedRunControlServer is called while another live Archon process holds the control socket for the same run id, and canConnect(path) succeeds.","commonSituations":"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.","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)."],"exampleFix":"// before\narchon run resume <runId>   # second instance -> endpoint already owned\n// after\narchon run stop <runId>     # terminate current owner\narchon run resume <runId>","handlingStrategy":"retry","validationCode":"// Before starting, test if an owner already answers:\nconst alive = await canConnect(socketPath); // your own helper\nif (alive) console.log('Run already owned; attach/stop instead of starting.');","typeGuard":null,"tryCatchPattern":"try {\n  await startDetachedRunControlServer(...);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Detached run control endpoint is already owned')) {\n    // fall back to attaching/querying the existing owner\n    const pid = await getDetachedRunOwnerPid(runId);\n  } else throw err;\n}","preventionTips":["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."],"tags":["ipc","unix-socket","detached-run","conflict"],"backgroundTag":"address-already-in-use","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}