{"record":{"id":"f8f307ac0498c60e","repo":"nanocoai/nanoclaw","slug":"failed-to-list-existing-sessions-for-adoption","errorCode":null,"errorMessage":"Failed to list existing sessions for adoption","messagePattern":"Failed to list existing sessions for adoption","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/container-runner.ts","lineNumber":388,"sourceCode":"  );\n}\n\n/**\n * Startup reconciliation: adopt what is still alive, stop what is not ours.\n *\n * This replaces the old reap-everything `cleanupOrphans()`. A surviving session\n * used to be destroyed on every host restart and its work recovered only\n * through the DB; now the host re-registers it and delivery resumes. The OneCLI\n * gateway resolves credentials per request on the host side, so an adopted\n * session's egress keeps working without any per-process state to rebuild.\n */\nexport async function adoptRunningSessions(): Promise<{ adopted: number; stopped: number }> {\n  const driver = getSessionDriver();\n  let snapshots: SupervisedSnapshot[];\n  try {\n    snapshots = await driver.listSessions(INSTALL_SLUG);\n  } catch (err) {\n    log.warn('Failed to list existing sessions for adoption', { err });\n    return { adopted: 0, stopped: 0 };\n  }\n\n  let adopted = 0;\n  let stopped = 0;\n  for (const { handle, phase } of snapshots) {\n    const session = handle.key.sessionId ? await getSession(handle.key.sessionId) : undefined;\n    // The snapshot's phase is the listing's own truth: a corpse arrives as\n    // 'terminal' (or not at all), so telling adoptable sessions apart needs\n    // no per-handle status() round trip. `stop()` on a corpse is still full\n    // teardown — a self-exited runtime needs its residue cleaned up.\n    if (!session || session.status !== 'active' || phase !== 'running') {\n      await handle.stop('orphan-at-startup').catch(() => {});\n      stopped += 1;\n      continue;\n    }\n    const runtime = registerRuntime(session.id, handle, handle.name, true);\n    runtime.stopReason = undefined;","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/container-runner.ts#L370-L406","documentation":"At startup the host could not list running Docker containers for adoption, so no orphaned session containers were adopted or stopped. Existing containers keep running but are unsupervised by this host process.","triggerScenarios":"`driver.listSessions(INSTALL_SLUG)` throws — Docker CLI failure, daemon not yet up when nanoclaw starts (race at boot), or permission issues on the docker socket.","commonSituations":"systemd user service starting before Docker; user not in the docker group; Docker desktop mid-restart.","solutions":["Verify `docker ps` works as the same user running nanoclaw","Restart the nanoclaw service after Docker is healthy: `systemctl --user restart nanoclaw`","Add Docker dependency ordering / retry to the service unit"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"execSync('docker ps'); // health gate before starting nanoclaw service","typeGuard":null,"tryCatchPattern":"try { await adoptRunningSessions(); } catch { /* retry after Docker is confirmed up */ }","preventionTips":["Order the service after Docker (systemd After=docker.service)","Verify `docker ps` works as the service user","Restart nanoclaw after Docker restarts"],"tags":["docker","adoption","startup","supervision"],"backgroundTag":"docker-daemon-unavailable","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}