Hmbown/CodeWhale · error

exec turn ended with status

Error message

exec turn ended with status {status}

What it means

After a CLI exec turn finishes, run_exec_agent checks the summary status; statuses of "failed", "canceled", or "interrupted" (or a missing status, reported as "unknown") are not successful completions, so the function bails with this error. It distinguishes a turn that ran but ended abnormally from one that threw an exception (error 893).

Solutions

  1. Check the status word in the message: interrupted/canceled usually means a signal or cancellation — rerun without interrupting.
  2. For "failed", inspect the session summary/logs for the failing step or tool output.
  3. For "unknown", verify the session summary was written by a compatible Codewhale version and is not truncated.
  4. Adjust the orchestrator to treat this exit as a turn-level failure and retry with backoff if appropriate.

Example fix

// before
codewhale exec "long task" &   # killed by timeout => status interrupted
// after
timeout 30m codewhale exec "long task" || echo "turn ended with $?, inspect summary"
Defensive patterns

Strategy: retry

Try / catch

let out = Command::new("codewhale").args(["exec", prompt]).output()?;
if !out.status.success() {
    let msg = String::from_utf8_lossy(&out.stderr);
    if msg.contains("ended with status interrupted") || msg.contains("ended with status canceled") {
        // reschedule rather than treating as a hard failure
    }
}

Prevention

When it happens

Trigger: Calling `codewhale exec` where the completed turn's summary reports status failed/canceled/interrupted — e.g. the model turn was cancelled by a signal, hit a failure classification, or the summary lacked a recognized status.

Common situations: User or orchestrator sent SIGINT/SIGTERM mid-turn; the turn hit the failure path recorded in the session summary; a bug or old session format produced a summary without a status string (shows as "unknown").

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/37a3f183a3aa4d85. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/exec_agent.rs:1452

        // after all in-session retries are exhausted) from genuine task
        // failures so supervisors and bench harnesses can tell them apart at
        // the process level without parsing the stream. Genuine failures
        // keep the historical `bail!` → exit 1 path.
        let exit_code = exec_failure_exit_code(summary.error_category.as_deref());
        if exit_code != 1 {
            eprintln!("Error: exec turn failed: {error}");
            let _ = io::stdout().flush();
            std::process::exit(exit_code);
        }
        bail!("exec turn failed: {error}");
    }

    if matches!(
        summary.status.as_deref(),
        Some("failed" | "canceled" | "interrupted")
    ) {
        let status = summary.status.as_deref().unwrap_or("unknown");
        bail!("exec turn ended with status {status}");
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{ExecAgentEvents, exec_automation_services, exec_disallowed_tools};
    use crate::core::engine::mock_engine_handle;
    use crate::core::engine::tool_catalog::REQUEST_USER_INPUT_NAME;
    use crate::core::events::{Event, TurnOutcomeStatus};
    use crate::core::ops::{Op, SubAgentSettlement};
    use codewhale_models::Usage;
    use std::time::{Duration, Instant};

    fn completed_parent(input_tokens: u32) -> Event {
        let usage = Usage {
            input_tokens,

View on GitHub (pinned to 73e0f67d83)