zeroclaw-labs/zeroclaw · error

needs_reassembly implies a step agent alias

Error message

needs_reassembly implies a step agent alias

What it means

While executing nested SOP steps, the turn engine computes needs_reassembly = step_needs_reassembly(agent_alias, step_alias), which is true only when step_alias is Some and differs from the current agent (turn/mod.rs:1603). This expect() asserts that consequence; a panic means the reassembly gate and the alias plumbing have desynchronized, an internal engine bug rather than user configuration.

Source

Thrown at crates/zeroclaw-runtime/src/agent/turn/mod.rs:1953

                    // A step that delegates to a different agent must run AS that
                    // agent — with that agent's own gated tools, policy, MCP
                    // scope, provider binding, and runtime controls — not the
                    // parent turn's. When the step names a different agent and a
                    // reassembly handle is available, re-assemble (and memoize)
                    // that agent's execution context; same-agent steps keep the
                    // parent context unchanged.
                    let step_alias = step.agent.as_deref();
                    // `agent_alias` is this loop's EFFECTIVE identity: a
                    // re-assembled sub-loop runs with its step agent as its own
                    // alias, so this comparison is correct at every nesting
                    // depth — a depth >= 2 step naming the outer agent compares
                    // against the re-assembled child's alias and re-assembles
                    // instead of inheriting the child's scope.
                    let needs_reassembly = step_needs_reassembly(agent_alias, step_alias);
                    let mut assembly_error: Option<anyhow::Error> = None;
                    if needs_reassembly {
                        let alias =
                            step_alias.expect("needs_reassembly implies a step agent alias");
                        if let Some(reassembly) = sop_reassembly {
                            if !exec_cache.contains_key(alias) {
                                match assemble_owned_execution(
                                    reassembly.config,
                                    alias,
                                    Arc::clone(&queued.engine),
                                    queued.audit.clone(),
                                    approval,
                                )
                                .await
                                {
                                    Ok(owned) => {
                                        exec_cache.insert(alias.to_string(), owned);
                                    }
                                    Err(e) => assembly_error = Some(e),
                                }
                            }
                        } else {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Reproduce with the SOP definition that triggers it and capture the backtrace, then check step_needs_reassembly and its callers around turn/mod.rs:1953 for divergence.
  2. Upgrade zeroclaw to the latest version where the gate and invariants are kept in sync.
  3. Report the issue upstream with the SOP config and stack trace since this is an engine invariant violation.
Defensive patterns

Strategy: validation

Validate before calling

// Before running an SOP, validate that every delegating step names a defined agent:
for step in &sop.steps {
    if let Some(alias) = &step.agent {
        anyhow::ensure!(agent_registry.contains(alias),
            "SOP step '{}' delegates to unknown agent '{alias}'", step.name);
    }
}

Try / catch

// Contain engine invariant panics per turn so one bad flow cannot kill the daemon:
let outcome = std::panic::catch_unwind(std::assert_unwind_safe(|| run_sop(sop).await));
if outcome.is_err() {
    tracing::error!("SOP '{}' hit an internal invariant; report with backtrace", sop.name);
}

Prevention

When it happens

Trigger: Running an SOP flow where a step delegates to a different agent alias. The panic would require needs_reassembly to be true while step_alias is None, impossible given the current gate implementation; realistically it appears only in forks where the gate or Option plumbing was modified.

Common situations: Running a patched zeroclaw-runtime after refactors to SOP step routing; version skew between crates that changed the reassembly gate contract; custom step-resolution logic injected before the turn loop.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/76abdba9743f350e. Report an issue: GitHub.