{"record":{"id":"2295e3ab8e710de4","repo":"nanocoai/nanoclaw","slug":"killing-container-past-absolute-ceiling","errorCode":null,"errorMessage":"Killing container past absolute ceiling","messagePattern":"Killing container past absolute ceiling","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/host-sweep.ts","lineNumber":276,"sourceCode":"\nfunction enforceRunningContainerSla(\n  inDb: InboundMailbox,\n  outDb: OutboundMailbox,\n  session: Session,\n  agentGroupId: string,\n): void {\n  const decision = decideStuckAction({\n    now: Date.now(),\n    heartbeatMtimeMs: heartbeatMtimeMs(agentGroupId, session.id),\n    containerStartedAtMs: getContainerStartedAtMs(session.id),\n    containerState: outDb.getContainerState(),\n    claims: outDb.getProcessingClaims(),\n  });\n\n  if (decision.action === 'ok') return;\n\n  if (decision.action === 'kill-ceiling') {\n    log.warn('Killing container past absolute ceiling', {\n      sessionId: session.id,\n      heartbeatAgeMs: decision.heartbeatAgeMs,\n      ceilingMs: decision.ceilingMs,\n    });\n    killContainer(session.id, 'absolute-ceiling');\n    resetStuckProcessingRows(inDb, outDb, session, 'absolute-ceiling');\n    return;\n  }\n\n  log.warn('Killing container — message claimed then silent', {\n    sessionId: session.id,\n    messageId: decision.messageId,\n    claimAgeMs: decision.claimAgeMs,\n    toleranceMs: decision.toleranceMs,\n  });\n  killContainer(session.id, 'claim-stuck');\n  resetStuckProcessingRows(inDb, outDb, session, 'claim-stuck');\n}","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/host-sweep.ts#L258-L294","documentation":"The 60s host sweep kills a session's container because its heartbeat file age exceeded the absolute ceiling even though the session is considered running. This is a last-resort SLA enforcement: the agent container is unresponsive past the hard limit, so it is killed and stuck processing rows are reset for retry by a fresh container.","triggerScenarios":"maintainSessionMailbox computes a kill-ceiling decision (heartbeatAgeMs > ceilingMs) from the heartbeat file at /workspace/.heartbeat; killContainer(session.id, 'absolute-ceiling') then resets processing_ack rows.","commonSituations":"Agent container hung on a long LLM call or deadlocked; host-gateway/network stall so the container can't touch the heartbeat; overloaded Docker host; container paused or OOM-frozen while host still lists it running.","solutions":["Check why the container was unresponsive: docker events, OOM kills, agent-runner logs before exit","If workloads legitimately exceed the ceiling, raise the SLA ceiling config for that group","Verify the heartbeat mount is writable inside the container (mount correctness)","If it recurs, capture docker inspect of the dying container before the sweep kills it to post-mortem"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Monitor heartbeat age and alert before the ceiling is reached","Keep long-running agent turns under the configured SLA or raise the ceiling deliberately","Verify the heartbeat mount is writable in the image (touch /workspace/.heartbeat at startup as a smoke test)"],"tags":["sweep","sla","heartbeat","container-kill","stuck-session"],"backgroundTag":"worker-heartbeat-timeout","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}