zeroclaw-labs/zeroclaw · error
Step {step_number} {phase} schema validation failed: {reason
Error message
Step {step_number} {phase} schema validation failed: {reason} What it means
The SOP engine validates each step's input and output JSON against the step's declared schema when `step_schema_enforce` is enabled. On mismatch, `fail_step_schema_validation` formats this reason, records a `step_schema_reject` transition event, logs a WARN failure event, and finishes the entire run with `SopRunStatus::Failed` — one invalid payload terminates the run.
Source
Thrown at crates/zeroclaw-runtime/src/sop/engine.rs:1999
}
let Some(schema) = step
.schema
.as_ref()
.and_then(|schema| schema.output.as_ref())
else {
return Ok(());
};
schema::validate_value(schema, output).map_err(|e| e.to_string())
}
fn fail_step_schema_validation(
&mut self,
run_id: &str,
step_number: u32,
phase: &str,
reason: String,
) -> Result<SopRunAction> {
let reason = format!("Step {step_number} {phase} schema validation failed: {reason}");
self.record_transition_event(
run_id,
"step_schema_reject",
Some(reason.clone()),
::serde_json::json!({
"step": step_number,
"phase": phase,
}),
);
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({
"run_id": run_id,
"step": step_number,
"phase": phase,
"reason": reason,View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the `{reason}` in the `step_schema_reject` event — it names the exact violation; adjust the producing prompt or caller so the payload conforms
- Fix or relax the step's `schema.input`/`schema.output` in the SOP definition to match reality (drop unjustified `required` entries, correct types)
- Add a repair loop: on rejection, re-prompt the model with the validation error before the run fails
- If strictness is not needed, set `step_schema_enforce = false` for the engine
Example fix
// before: schema demands a field the model omits
{"schema":{"output":{"required":["summary","sources"]}}}
// payload: {"summary":"..."}
// after: only require what the step truly needs
{"schema":{"output":{"required":["summary"],"properties":{"sources":{"type":"array"}}}}}
// payload: {"summary":"...","sources":[]} Defensive patterns
Strategy: validation
Validate before calling
fn required_fields_present(schema: &serde_json::Value, payload: &serde_json::Value) -> bool {
match schema.get("required").and_then(|r| r.as_array()) {
None => true,
Some(req) => req
.iter()
.all(|k| payload.get(k.as_str().unwrap_or_default()).is_some()),
}
}
// run against the step's schema.input/schema.output before submitting each phase Prevention
- Keep step schemas minimal and cover them with fixture payloads in tests
- On a step_schema_reject event, feed the reason back to the model and repair the payload instead of letting the run fail
- Pin prompts and schemas together in the SOP definition so they cannot drift independently
When it happens
Trigger: A step declares `schema.input`/`schema.output` and enforcement is on, but the submitted input or the model-produced output misses a required field, uses a wrong type, or violates a constraint; validate_step_input/validate_step_output return the validator message which lands in `{reason}`.
Common situations: LLM omits fields that look optional but are required; schemas tightened after SOPs were written; enum/const drift after prompt changes; nested objects with wrong shapes.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- amqp.{}: dispatch = {:?} routes to the SOP engine but no SOP
- WhatsApp interactive buttons require 1..=3 options (got {});
- WhatsApp interactive list requires at least one section
- WhatsApp interactive list capped at 10 sections (got {})
- WhatsApp interactive list section '{}' capped at 10 rows (go
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/affa60ce990ed3d2.
Report an issue: GitHub.