{"record":{"id":"74e268921fd20328","repo":"astrid-runtime/astrid","slug":"delete-of-derived-left-unreclaimed-state-det","errorCode":null,"errorMessage":"delete of '{derived}' left unreclaimed state: {details}","messagePattern":"delete of '(.+?)' left unreclaimed state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/agent/spawn.rs","lineNumber":274,"sourceCode":"    let body = admin\n        .request(AdminRequestKind::AgentDelete {\n            principal: derived.clone(),\n        })\n        .await\n        .with_context(|| format!(\"could not delete '{derived}'\"))?;\n    let outcome = into_result(body).with_context(|| format!(\"delete of '{derived}' failed\"))?;\n    if let astrid_events::kernel_api::AdminResponseBody::Success(value) = outcome\n        && let Some(errors) = value\n            .get(\"cleanup_errors\")\n            .and_then(|value| value.as_array())\n        && !errors.is_empty()\n    {\n        let details = errors\n            .iter()\n            .filter_map(|error| error.as_str())\n            .collect::<Vec<_>>()\n            .join(\"; \");\n        return Err(anyhow!(\n            \"delete of '{derived}' left unreclaimed state: {details}\"\n        ));\n    }\n    eprintln!(\"[spawn] tore down '{derived}' (footprint reclaimed)\");\n    Ok(())\n}\n\n/// First 8 hex chars of the session uuid — short but unique per spawn.\nfn short_suffix(session: &SessionId) -> String {\n    session.0.simple().to_string()[..8].to_string()\n}\n","sourceCodeStart":256,"sourceCodeEnd":286,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/agent/spawn.rs#L256-L286","documentation":"Raised in teardown when the delete of the spawned derived agent leaves unreclaimed state: one or more cleanup steps recorded errors, which are joined into the details string. The command fails rather than silently leaving orphaned sessions/footprints behind.","triggerScenarios":"The delete call partially succeeded: e.g. the session could not be closed, workspace files could not be removed, or the daemon rejected the delete because the agent was still busy.","commonSituations":"Agent still processing a cancelled job when delete arrives, filesystem permissions preventing footprint reclamation, daemon connectivity hiccup during cleanup.","solutions":["Inspect the {details} suffix to see which state was unreclaimed","Retry the delete/teardown once the agent is fully idle","Manually delete the leftover session/workspace via the daemon admin commands"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"// ensure the agent is idle before teardown\nif !agent_is_idle(&derived).await { wait_until_idle(&derived).await; }","typeGuard":null,"tryCatchPattern":"match teardown(...).await { Err(e) if e.to_string().contains(\"left unreclaimed state\") => { eprintln!(\"{e:#}; inspect details and retry delete\"); manual_cleanup(&derived).await }, other => other }","preventionTips":["Cancel jobs and wait for the agent to be idle before deleting","Run teardown with adequate filesystem permissions","Check the daemon accepted the delete before assuming cleanup succeeded"],"tags":["cleanup","lifecycle","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}