Hmbown/CodeWhale · error
Turn output allowance does not match its schema
Error message
Turn output allowance does not match its schema
What it means
A turn record may carry `max_output_tokens` only when its `schema_version` equals `OUTPUT_LIMIT_RUNTIME_SCHEMA_VERSION`; the presence/absence of the field must match the schema exactly. `validate_output_token_limit` enforces this invariant both ways (field without the version, or version without the field).
Solutions
- Set the record's `schema_version` to `OUTPUT_LIMIT_RUNTIME_SCHEMA_VERSION` when writing `max_output_tokens`.
- Set `max_output_tokens: None` for records on other schema versions.
- Fix the writer code so version and field are updated together.
Example fix
// before
TurnRecord { schema_version: 2, max_output_tokens: Some(4096), .. }
// after
TurnRecord { schema_version: OUTPUT_LIMIT_RUNTIME_SCHEMA_VERSION, max_output_tokens: Some(4096), .. } Defensive patterns
Strategy: validation
Validate before calling
fn output_tokens_valid(r: &TurnRecord) -> bool { r.max_output_tokens.is_some() == (r.schema_version == OUTPUT_LIMIT_RUNTIME_SCHEMA_VERSION) } Try / catch
match store.load_turn(&turn_id) { Err(e) if e.contains("does not match its schema") => { quarantine_record(&turn_id); continue_without(e) }, Err(e) => Err(e.into()), Ok(t) => Ok(t) } Prevention
- Update schema_version and new fields together in the writer
- Add a round-trip test for TurnRecord serialization
- Never hand-edit turn record files
When it happens
Trigger: Loading or constructing a `TurnRecord` where `max_output_tokens.is_some()` disagrees with `schema_version == OUTPUT_LIMIT_RUNTIME_SCHEMA_VERSION`.
Common situations: Hand-edited or migrated turn files; code that sets `max_output_tokens` but forgets to bump the schema version (or vice versa) when writing records.
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
- Automation run schema v
- Automation schema v is newer than supported v
- Checkpoint schema v is newer than supported v
- Codewhale stream-json contained an unknown event type
- Codewhale stream-json schema did not match v0.9.1
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/693309cd6e2fd3b9.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/runtime_threads.rs:1054
/// idempotency bridge between a claimed mail envelope and the existing
/// turn queue; ordinary external-user turns leave it unset.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub agent_mail_message_id: Option<String>,
}
impl TurnRecord {
fn validate_output_token_limit(&self) -> Result<()> {
if self.schema_version > MAX_SUPPORTED_RUNTIME_SCHEMA_VERSION {
bail!(
"Turn schema v{} is newer than supported v{}",
self.schema_version,
MAX_SUPPORTED_RUNTIME_SCHEMA_VERSION
);
}
if self.max_output_tokens.is_some()
!= (self.schema_version == OUTPUT_LIMIT_RUNTIME_SCHEMA_VERSION)
{
bail!("Turn output allowance does not match its schema");
}
Ok(())
}
pub(crate) fn effective_provider_label(&self) -> Option<&str> {
self.effective_provider_id
.as_deref()
.filter(|identity| !identity.trim().is_empty())
.or_else(|| {
self.effective_provider
.as_deref()
.filter(|provider| !provider.trim().is_empty())
})
}
fn persist_effective_route(&mut self, route: &EffectiveRouteEnvelope) {
let route = route.sanitized_for_persistence();
self.effective_provider = Some(route.provider.as_str().to_string());View on GitHub (pinned to 73e0f67d83)