Hmbown/CodeWhale · error · anyhow::Error
runtime event stream ended before turn.completed
Error message
runtime event stream ended before turn.completed
What it means
After consuming the runtime's SSE event stream to completion, the client looks for a terminal turn.completed event. If the stream ends without one, it throws this error because a turn's outcome could not be confirmed.
Solutions
- Check the runtime process logs for a crash or restart during the turn.
- Retry the turn; transient disconnections are the most common cause.
- Look at proxy/gateway idle-timeout settings and raise them for long-running turns.
- Upgrade the runtime if it can terminate a stream without a terminal event (a known bug).
Defensive patterns
Strategy: retry
Try / catch
// Rust
match turn.wait_completed() {
Err(e) if e.to_string().contains("ended before turn.completed") => {
// treat as indeterminate outcome; check runtime liveness, then retry once
}
other => other,
} Prevention
- Set proxy/gateway idle timeouts above your longest expected turn.
- Monitor runtime process health (OOM, restarts) during long turns.
- Retry turns that end without a terminal event; treat the outcome as unknown.
When it happens
Trigger: The runtime's event stream closes (EOF on the HTTP chunked response) after emitting events but before sending turn.completed — e.g. the runtime crashed, the connection dropped, or the server ended the stream early.
Common situations: Runtime process killed mid-turn (OOM, panic, deploy restart); idle connection closed by a proxy timeout; runtime bug that skips the terminal event.
Related errors
- Runtime event stream ended inside a frame
- runtime SSE frame exceeded
- SSE stream idle timeout after
- SSE stream idle timeout after
- SSE stream idle timeout after
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/2cd399cbaaad48cd.
Report an issue: GitHub.
Appendix: source
Thrown at crates/app-server/src/lib.rs:1982
channel: ResponseChannel::Text,
});
}
}
}
"turn.completed" => {
let status = turn_terminal_status(&payload);
let error = payload
.pointer("/turn/error")
.and_then(Value::as_str)
.map(str::to_string);
return Ok((last_seq, status, error));
}
_ => {}
}
}
}
bail!("runtime event stream ended before turn.completed")
}
#[cfg(test)]
fn from_base_url_for_test(base_url: String) -> Self {
install_rustls_crypto_provider();
Self {
base_url,
client: codewhale_release::platform_http_client_builder()
.timeout(Duration::from_secs(5))
.build()
.expect("build reqwest test client"),
auth_token: None,
child: None,
last_seq_by_thread: HashMap::new(),
}
}
}
View on GitHub (pinned to 73e0f67d83)