{"record":{"id":"381728ad0a67f639","repo":"coleam00/Archon","slug":"err-as-error-message","errorCode":null,"errorMessage":"(err as Error).message","messagePattern":"\\(err as Error\\)\\.message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/services/cleanup-service.ts","lineNumber":218,"sourceCode":"      });\n      continue;\n    }\n    if (row.days_since_created < daysStale) {\n      report.skipped.push({\n        id: row.id,\n        reason: `${Math.floor(row.days_since_created)}d old (< ${daysStale}d threshold)`,\n      });\n      continue;\n    }\n    try {\n      await backend.destroy(row.id);\n      report.removed.push(row.id);\n      // No runId: the reap only happens when no run can still claim this env.\n      getLog().info({ envId: row.id }, 'container_env_reaped');\n    } catch (err) {\n      report.errors.push({ id: row.id, error: (err as Error).message });\n      getLog().warn({ err, envId: row.id }, 'container_env_reap_failed');\n    }\n  }\n  return report;\n}\n\n/**\n * Called when a platform conversation is closed (e.g., GitHub issue/PR closed)\n * Cleans up the associated isolation environment unless a workflow run can still\n * claim it. Conversation references are data, not locks (#2868).\n */\nexport async function onConversationClosed(\n  platformType: string,\n  platformConversationId: string,\n  options?: { merged?: boolean }\n): Promise<void> {\n  getLog().info({ platformType, platformConversationId }, 'conversation_closed');\n\n  // Find the conversation\n  const conversation = await conversationDb.getConversationByPlatformId(","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/core/src/services/cleanup-service.ts#L200-L236","documentation":"This is not a thrown error but a captured error message recorded in the cleanup report's `errors` array by cleanupContainerEnvironments. When the reaper fails to remove a stale container isolation environment (the container-runtime removal call or its database row cleanup throws), the per-row failure is caught so one bad environment does not abort the whole reap. The message plus a structured 'container_env_reap_failed' warn log carry the full evidence.","triggerScenarios":"Running the container environment reap (via containerReport or report) over stale rows where the container runtime call fails: container already removed out-of-band but still in the DB, docker/podman daemon unreachable, runtime rejecting removal of a running or locked container, or volume/filesystem cleanup failing.","commonSituations":"Docker daemon restarted or not running when cleanup fires; a container manually deleted with `docker rm` leaving an orphaned DB row; permission errors on the docker socket in service deployments; container in a state that refuses removal (paused, dead with locked resources).","solutions":["Inspect the structured 'container_env_reap_failed' log entry for the full err object — the captured message is only the summary.","Verify the container runtime (docker/podman) is up and the socket is accessible.","Re-run the reap after the runtime recovers; the row stays and is retried on the next pass.","If the DB row is orphaned (container truly gone), remove the row through the normal env-removal path so DB and runtime re-converge."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before triggering reap\nconst dockerOk = await Bun.spawn(['docker', 'info'], { stdout: 'ignore', stderr: 'ignore' }).exited.then(c => c === 0);\nif (!dockerOk) throw new Error('container runtime unavailable; defer reap');","typeGuard":"function isRecordedReapError(r: unknown): r is { id: string; error: string } {\n  return typeof r === 'object' && r !== null\n    && typeof (r as { id?: unknown }).id === 'string'\n    && typeof (r as { error?: unknown }).error === 'string'\n    && (r as { error: string }).error.length > 0;\n}","tryCatchPattern":"try {\n  await reapEnvironment(row);\n  report.removed.push(row.id);\n} catch (err) {\n  getLog().warn({ err, envId: row.id }, 'container_env_reap_failed');\n  report.errors.push({ id: row.id, error: (err as Error).message });\n  // continue with remaining rows — one failure must not abort the sweep\n}","preventionTips":["Check docker/podman daemon health before scheduling cleanup passes.","Reconcile DB rows against `docker ps -a` to drop orphaned rows.","Grant the reaper access to the docker socket (group membership) in service deployments.","Alert on container_env_reap_failed logs so failures are fixed before rows accumulate."],"tags":["cleanup","containers","docker"],"backgroundTag":"container-runtime-unavailable","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}