Agent crash policy
When your sandboxed agent process throws in a handler or exits unexpectedly, the runner applies the project setting agent_crash_policy. This page explains both policies, how they interact with shared_child_per_session, and what client messages can (and cannot) survive a restart_child cycle.
Where to configure
- Dashboard: Project overview → Runner settings → Agent crash policy.
- CLI:
voicethere projects settings set agent_crash_policy <value> - API:
PATCH /projects/:projectId/runner-settingswith{ "key": "agent_crash_policy", "value": "…" }— see Control plane API.
Changes are stored on the project immediately but apply to live traffic only after you Deploy to cloud (runner env is baked at deploy time as RUNNER_AGENT_CRASH_POLICY).
Values
| Value | Default | Summary |
|---|---|---|
disconnect_all | Yes | Tear down affected WebRTC sessions on the runner after notifying clients with a non-recoverable session error. |
restart_child | No | Kill and respawn the sandboxed agent child, re-register live sessions, keep WebRTC / data channels up, and notify clients with a recoverable session error. |
disconnect_all
Use this when a crashed agent should end the call cleanly rather than continue with a fresh process. Typical for strict single-tenant voice pods or when you prefer the client to reconnect explicitly.
- Runner detects
agent_errorIPC (handler throw) or an unexpected childexit. - Clients receive a
session_errorwith a non-recoverable code such asAGENT_HANDLER_FAILEDorAGENT_CHILD_CRASHED(see Session errors). - Optional crash TTS (project session setting
error_message) may play on voice sessions. - Sessions on that crash scope are disconnected / torn down.
Scope with dedicated children: when shared_child_per_session=false (Advanced+), each session has its own agent child. Crashing session A does nottear down session B on the same pod — only A's child and session are affected.
Scope with a shared child: when shared_child_per_session=true, one child serves every session on the pod. A crash under disconnect_all ends all sessions on that pod that share the child.
restart_child
Use this when you want the media path to stay up while the agent process is replaced — for example multiplayer or long-lived data sessions where reconnecting WebRTC would be worse than a brief agent restart.
- Runner sets an internal restart window and kills the sandboxed child.
- A new child is spawned and each still-live session is re-registered.
- Clients receive
AGENT_CHILD_CRASHED_RESTARTEDwithrecoverable: true. WebRTC and data channels stay connected. - The new child runs
onSessionStartagain (your agent may greet / re-init state). - Buffered client→agent IPC is flushed after the child sends
session_start_ack.
With shared_child_per_session=false, only the crashed session's child restarts; peer sessions on the same pod keep their own children and continue uninterrupted.
Message buffering during restart
While the child is restarting, the runner buffers parent→child user IPC so work is not blindly dropped:
data_channel_message/data_channel_binaryspeech_event(voice turns)idle_timeout
Those messages are held until the new child acknowledges session start, then delivered in order.
What is salvaged
- Messages that arrive on the runner during the kill→spawn→ack window (restart gate).
- Messages still waiting on the runner's outbound serial queue that have not finished
child.sendyet — they are moved into the restart buffer instead of being cleared.
Residual data loss (important)
The runner cannot unsend bytes already handed to a dying child over Node IPC. If the client sends a crash trigger and another message in the same instant, the follow-up may already have been child.send'd to the old process before the runner learns about the crash. Those already-sent payloads are not recovered.
In practice:
- Queued on the runner, not yet sent → salvaged and replayed after restart (minimal loss).
- Already sent to the dying child → may be lost; design agents and clients to tolerate a rare gap or wait for
AGENT_CHILD_CRASHED_RESTARTED/ a fresh agent ready signal before critical follow-ups. - Detection is an IPC round-trip (or process
exit), not the next JavaScript tick afterchild.send.
Client expectations
- Handle
onSessionErrorfor both policies (catalog). - On
restart_child, treatAGENT_CHILD_CRASHED_RESTARTEDas recoverable — keep the session; the agent may speak again afteronSessionStart. - Do not assume every in-flight data-channel or speech turn across the crash boundary is delivered; prefer idempotent messages or a short pause after the restart notify for critical commands.
CLI examples
# List effective runner settings voicethere projects settings list # Prefer keep-alive restart (redeploy after set) voicethere projects settings set agent_crash_policy restart_child voicethere deploy --wait # Fail closed: disconnect on crash voicethere projects settings set agent_crash_policy disconnect_all voicethere deploy --wait