# X_LIFECYCLE_DRAINED

## Means

a drained process cannot become ready again

## Typical cause

a role called `markReady()` in a process whose lifecycle has already drained — a second `httpServer().start()`, or a boot that started a role after SIGTERM arrived. `state` never leaves `stopped` and `drain()` memoizes, so the socket such a role binds answers 503 to every request and nothing is left to close it: measured, still accepting connections after its own `stop()` returned. A container role (`runRole`) whose boot meets it because SIGTERM arrived mid-boot does NOT surface it: that is a rollout superseding the pod, so the boot finishes the drain, logs `ultimate boot interrupted by shutdown` at info with this code, and exits 0 (`As of 2026-10-17`)

## Fix

start every role BEFORE the first drain — a drained process is on its way out and is replaced, never reused. In a test, call `resetLifecycle()` from `@ultimat3/core` between the drain and the next `start()`

[Core and runtime](/error-codes#core-and-runtime)
