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

target V{target} exceeds CURRENT_SCHEMA_VERSION (V{CURRENT_S

Error message

target V{target} exceeds CURRENT_SCHEMA_VERSION (V{CURRENT_SCHEMA_VERSION})

What it means

run_chain_until refuses any target above CURRENT_SCHEMA_VERSION because migration steps only exist up to the compiled version (V3). This is the bounds check that keeps the MIGRATION_STEPS[from..target] slice from indexing past its end, and it catches requests for schema versions the running binary cannot produce.

Source

Thrown at crates/zeroclaw-config/src/migration.rs:829

const _: () = assert!(
    MIGRATION_STEPS.len() as u32 == CURRENT_SCHEMA_VERSION,
    "MIGRATION_STEPS must have exactly one entry per schema version \
     (length = CURRENT_SCHEMA_VERSION, including the slot-0 padding)",
);

/// Run the typed migration chain from `from` up to `CURRENT_SCHEMA_VERSION`.
/// `from` must be `< CURRENT_SCHEMA_VERSION` (caller checks).
fn run_chain(value: toml::Value, from: u32) -> Result<toml::Value> {
    run_chain_until(value, from, CURRENT_SCHEMA_VERSION)
}

fn run_chain_until(value: toml::Value, from: u32, target: u32) -> Result<toml::Value> {
    if target < from {
        anyhow::bail!("cannot migrate backwards from V{from} to V{target}");
    }
    if target > CURRENT_SCHEMA_VERSION {
        anyhow::bail!(
            "target V{target} exceeds CURRENT_SCHEMA_VERSION (V{CURRENT_SCHEMA_VERSION})"
        );
    }

    let mut cur = value;
    for step in &MIGRATION_STEPS[from as usize..target as usize] {
        cur = step(cur)?;
    }
    Ok(cur)
}

pub(crate) fn sync_table(doc: &mut toml_edit::Table, new: &toml::Table) {
    // Drop keys not present in new
    let to_remove: Vec<String> = doc
        .iter()
        .map(|(k, _)| k.to_string())
        .filter(|k| !new.contains_key(k))
        .collect();

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use CURRENT_SCHEMA_VERSION as the target instead of a literal number.
  2. Upgrade the binary if you genuinely need the newer schema version.
  3. Validate or clamp the target argument before calling the chain.

Example fix

// before
let migrated = run_chain_until(value, from, 4)?; // target exceeds CURRENT_SCHEMA_VERSION

// after
let migrated = run_chain_until(value, from, CURRENT_SCHEMA_VERSION)?;
Defensive patterns

Strategy: validation

Validate before calling

// never hardcode a schema literal; derive it
let target = target.min(CURRENT_SCHEMA_VERSION);
assert!(target >= from, "downgrades unsupported");
let migrated = run_chain_until(value, from, target)?;

Try / catch

match run_chain_until(value, from, target) {
    Err(e) if e.to_string().contains("exceeds CURRENT_SCHEMA_VERSION") => {
        // retry with target = CURRENT_SCHEMA_VERSION
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling run_chain_until(value, from, target) with target > 3 — e.g. requesting generate() at V4 on a V3 binary, or forwarding a hardcoded future version that outlived the binary it was written against.

Common situations: Code written against a newer ZeroClaw that hardcodes a higher target version; a user-supplied version from config or CLI forwarded unclamped into the migration chain.

Related errors


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