Hmbown/CodeWhale · error

sub-agent transcript message index {index} does not follow {

Error message

sub-agent transcript message index {index} does not follow {}

What it means

Each message record's index must equal the number of messages already read (dense 0-based sequence). This error fires when a record's index skips ahead, repeats, or is out of order — the loader refuses sequences with gaps or duplicates because they can hide dropped or duplicated messages.

Source

Thrown at crates/tui/src/tools/subagent/mod.rs:7612

    {
        return Err(anyhow!(
            "sub-agent transcript artifact header does not match agent {agent_id}"
        ));
    }

    let mut messages = Vec::new();
    for line in lines.filter(|line| !line.trim().is_empty()) {
        let record: Value = serde_json::from_str(line)?;
        if record.get("kind").and_then(Value::as_str) != Some("message") {
            return Err(anyhow!("unknown sub-agent transcript artifact record"));
        }
        let index = record
            .get("index")
            .and_then(Value::as_u64)
            .and_then(|value| usize::try_from(value).ok())
            .ok_or_else(|| anyhow!("sub-agent transcript message is missing its index"))?;
        if index != messages.len() {
            return Err(anyhow!(
                "sub-agent transcript message index {index} does not follow {}",
                messages.len()
            ));
        }
        let message = serde_json::from_value::<Message>(
            record
                .get("message")
                .cloned()
                .ok_or_else(|| anyhow!("sub-agent transcript record is missing its message"))?,
        )?;
        messages.push(message);
    }
    Ok(messages)
}

fn remove_subagent_transcript_artifact(state_root: &Path, agent_id: &str) -> Result<bool> {
    let state_root = normalize_subagent_workspace(state_root);
    let path = checked_subagent_transcript_artifact_path(&state_root, agent_id)?;

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Repair the artifact so indexes run densely 0..n with no gaps or repeats.
  2. Regenerate the transcript by re-running the sub-agent when manual renumbering is risky.
  3. Never append to an artifact from more than one process; only the owning persister may write.
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify dense 0-based ordering before loading:
for (expected, line) in raw.lines().skip(1).filter(|l| !l.trim().is_empty()).enumerate() {
    let v: serde_json::Value = serde_json::from_str(line)?;
    if v["index"].as_u64() != Some(expected as u64) { /* gap/ordering issue at {expected} */ }
}

Type guard

fn indexes_are_dense(lines: impl Iterator<Item = String>) -> bool {
    lines.enumerate().all(|(i, l)| {
        serde_json::from_str::<serde_json::Value>(&l)
            .map(|v| v["index"].as_u64() == Some(i as u64))
            .unwrap_or(false)
    })
}

Try / catch

match load_subagent_transcript_artifact(&state_root, agent_id) {
    Err(e) if e.to_string().contains("does not follow") => { /* renumber 0..n or regenerate */ }
    r => r?,
}

Prevention

When it happens

Trigger: Lines reordered by an external process; a duplicated record pasted in; a record deleted manually leaving a gap; another writer numbering from 1 instead of 0.

Common situations: Manual artifact surgery; concurrent appends by two processes; migration scripts that renumber incorrectly.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/d11aec37e3bd8ce3. Report an issue: GitHub.