Hmbown/CodeWhale · error
the cloud agent runner panicked
Error message
the cloud agent runner panicked
What it means
join_runner waits on a spawned cloud-agent runner thread via JoinHandle::join. A panic inside that thread surfaces as Err(()) from join, which is converted into "the cloud agent runner panicked". The real panic payload is discarded, so this indicates an internal crash in the runner thread, not a user-input problem.
Solutions
- Re-run the command; transient panics may not reproduce
- Check the job in the store — the code still reloads and prints the job after join fails
- Capture RUST_BACKTRACE=1 output to find the panic site in the runner
- Report the panic with the job id and CLI version; this is an internal invariant violation
Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = run_with(...).await {
if e.to_string().contains("runner panicked") {
eprintln!("cloud agent crashed; job state may still be readable from the store");
}
return Err(e);
} Prevention
- Set RUST_BACKTRACE=1 when reproducing so the panic site is captured
- Keep CLI and cloud service versions compatible
- Avoid feeding untrusted/malformed job payloads into the runner
- Treat occurrences as bugs to report — this path is not an expected failure mode
When it happens
Trigger: The background thread spawned to run/monitor the cloud agent job panicked (unexpected None unwrap, assertion, index panic, or an explicit panic in runner code).
Common situations: A cloud job returns malformed data the runner doesn't expect, a network callback unwraps a failed request, or a version mismatch between CLI and cloud service trips an invariant.
Related errors
- ApplyPatchPreflight should serialize
- bing result regex pattern is valid
- bing snippet regex pattern is valid
- bing title regex pattern is valid
- bounded to model output cap
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/c49f08f73808f4d5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/dispatch.rs:164
let job_id = outcome_job_id(&outcome).unwrap_or_default();
write_outcome(out, outcome)?;
join_runner(out, &store, &job_id, runner)
}
/// The CLI stays attached to a confirmed run: the card prints immediately,
/// then the process waits for the runner so a paid sandbox is never
/// orphaned by an early exit. Ctrl-C exits the wait; the job stays recorded
/// and `--cancel` tears the sandbox down.
fn join_runner<W: Write>(
out: &mut W,
store: &CloudJobStore,
id: &str,
runner: Option<std::thread::JoinHandle<()>>,
) -> Result<()> {
if let Some(runner) = runner {
runner
.join()
.map_err(|_| anyhow::anyhow!("the cloud agent runner panicked"))?;
if !id.is_empty()
&& let Ok(job) = store.load(id)
{
writeln!(out, "{}", format_job(&job))?;
}
}
Ok(())
}
fn outcome_job_id(outcome: &DispatchOutcome) -> Option<String> {
match outcome {
DispatchOutcome::Proposal(job)
| DispatchOutcome::Refused(job)
| DispatchOutcome::Accepted(job) => Some(job.id.clone()),
}
}
/// Newest jobs for the status card's receipts section (best effort — anView on GitHub (pinned to 73e0f67d83)