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
- 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.
- Upgrade zeroclaw to the latest version where the gate and invariants are kept in sync.
- 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
- Validate SOP step agent references against the agent registry before execution.
- Run unmodified upstream releases; these expects guard engine-internal invariants, not config.
- Capture backtraces (RUST_BACKTRACE=1) when reproducing to include in an upstream report.
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
- owned implies a reassembly handle
- Schema missing required 'type' field
- purge_agent not supported by this memory backend
- rename_agent not supported by this memory backend
- memory backend '{}' does not support StoreOptions kind/pinne
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/76abdba9743f350e.
Report an issue: GitHub.