zeroclaw-labs/zeroclaw · error · anyhow::Error

failed step output is not captured into procedural memory

Error message

failed step output is not captured into procedural memory

What it means

capture_successful_run refuses to distill any run in which at least one step result has status SopStepStatus::Failed. Procedural memory only records fully green procedures; capturing a run with a failed step would enshrine a broken sequence (or its partial outputs) as a reusable SOP.

Source

Thrown at crates/zeroclaw-runtime/src/sop/procedural_memory.rs:104

    engine: &SopEngine,
    run_id: &str,
    requested_by: Option<String>,
) -> Result<ProposalRecord> {
    let run = engine
        .get_run(run_id)
        .ok_or_else(|| anyhow::Error::msg(format!("SOP run not found: {run_id}")))?;
    if run.status != SopRunStatus::Completed {
        bail!("only completed SOP runs can be captured");
    }
    if run.step_results.is_empty() {
        bail!("completed run has no step results to distill");
    }
    if run
        .step_results
        .iter()
        .any(|step| matches!(step.status, super::types::SopStepStatus::Failed))
    {
        bail!("failed step output is not captured into procedural memory");
    }

    let sop = engine
        .get_sop(&run.sop_name)
        .ok_or_else(|| anyhow::Error::msg(format!("SOP not loaded: {}", run.sop_name)))?;
    let manifest_toml = read_or_default_manifest(sop)?;
    let procedure_markdown = append_captured_notes(sop, run_id, &run.step_results)?;
    create_proposal(
        engine,
        ProposalDraft {
            sop_name: sop.name.clone(),
            description: sop.description.clone(),
            manifest_toml: Some(manifest_toml),
            procedure_markdown,
            source_run_id: Some(run_id.to_string()),
            requested_by,
        },
    )

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Re-run the SOP from scratch and only capture runs where every step succeeded.
  2. Fix the failing step (its inputs, tool, or environment) before capture.
  3. Pre-check run.step_results for any Failed status and skip capture instead of erroring.

Example fix

// before: capture a run that had a failed step patched over by approval
let p = capture_successful_run(&engine, run_id, None).await?; // bails

// after: only capture all-green runs
let run = engine.get_run(run_id).context("run missing")?;
let all_green = run.step_results.iter()
    .all(|s| s.status != SopStepStatus::Failed);
if run.status == SopRunStatus::Completed && all_green {
    let p = capture_successful_run(&engine, run_id, None).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

let Some(run) = engine.get_run(run_id) else {
    anyhow::bail!("SOP run not found: {run_id}");
};
anyhow::ensure!(
    run.step_results
        .iter()
        .all(|s| s.status != SopStepStatus::Failed),
    "run contains failed steps; re-run before capture"
);

Type guard

fn is_all_green(run: &SopRun) -> bool {
    run.step_results
        .iter()
        .all(|s| s.status != SopStepStatus::Failed)
}

Try / catch

match capture_successful_run(&engine, run_id, None).await {
    Err(e) if e.to_string().contains("failed step output") => {
        // fix the failing step and re-run the SOP end to end before capturing
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling capture on a Completed run whose history includes a step that failed (e.g. a step failed, was retried or skipped past, and the run later completed). Any single Failed entry in run.step_results trips the guard.

Common situations: Runs where a failed step was bypassed by an operator approve/deny and execution continued; flaky steps that failed once then passed on a later manual run; attempts to capture 'mostly worked' runs.

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 zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/5767b8fb224b4a94. Report an issue: GitHub.