zed-industries/zed · error

unrecognized serialized thread version: {version:?}

Error message

unrecognized serialized thread version: {version:?}

What it means

`SerializedThread::from_json` reads the `version` field of a saved agent thread and dispatches on it: `"0.1.0"` upgrades via `SerializedThreadV0_1_0`, `"0.2.0"` (`SerializedThread::VERSION`) parses directly, and any other string bails here. It means the JSON is a thread store from a Zed build whose schema version this code does not know.

Source

Thrown at crates/agent/src/legacy_thread.rs:66

    pub model: String,
}

impl SerializedThread {
    pub const VERSION: &'static str = "0.2.0";

    pub fn from_json(json: &[u8]) -> Result<Self> {
        let saved_thread_json = serde_json::from_slice::<serde_json::Value>(json)?;
        match saved_thread_json.get("version") {
            Some(serde_json::Value::String(version)) => match version.as_str() {
                SerializedThreadV0_1_0::VERSION => {
                    let saved_thread =
                        serde_json::from_value::<SerializedThreadV0_1_0>(saved_thread_json)?;
                    Ok(saved_thread.upgrade())
                }
                SerializedThread::VERSION => Ok(serde_json::from_value::<SerializedThread>(
                    saved_thread_json,
                )?),
                _ => anyhow::bail!("unrecognized serialized thread version: {version:?}"),
            },
            None => {
                let saved_thread =
                    serde_json::from_value::<LegacySerializedThread>(saved_thread_json)?;
                Ok(saved_thread.upgrade())
            }
            version => anyhow::bail!("unrecognized serialized thread version: {version:?}"),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SerializedThreadV0_1_0(
    // The structure did not change, so we are reusing the latest SerializedThread.
    // When making the next version, make sure this points to SerializedThreadV0_2_0
    SerializedThread,
);

View on GitHub (pinned to f4178619ac)

Solutions

  1. Reopen the thread with the Zed version that wrote it and export/complete it there.
  2. Upgrade Zed to at least the version that produced the file.
  3. If the version was hand-edited, restore the original `"0.1.0"`/`"0.2.0"` value — but only if the body really matches that schema.
  4. As a developer adding a schema bump, register the new constant in the `match` in `legacy_thread.rs::from_json` and add an upgrade path.

Example fix

// crates/agent/src/legacy_thread.rs — adding a new schema version
// before
match version.as_str() {
    SerializedThreadV0_1_0::VERSION => { /* upgrade */ }
    SerializedThread::VERSION => { /* parse */ }
    _ => anyhow::bail!("unrecognized serialized thread version: {version:?}"),
}
// after
match version.as_str() {
    SerializedThreadV0_1_0::VERSION => { /* upgrade */ }
    SerializedThreadV0_2_0::VERSION => { /* upgrade */ }
    SerializedThread::VERSION => { /* parse */ }
    _ => anyhow::bail!("unrecognized serialized thread version: {version:?}"),
}
Defensive patterns

Strategy: validation

Validate before calling

// Inspect the version before deserializing:
let value: serde_json::Value = serde_json::from_slice(json)?;
const KNOWN: &[&str] = &[SerializedThreadV0_1_0::VERSION, SerializedThread::VERSION];
match value.get("version") {
    Some(serde_json::Value::String(v)) if KNOWN.contains(&v.as_str()) => { /* safe to call from_json */ }
    _ => { /* unknown version — migrate or reject with a clear message */ }
}

Type guard

fn known_thread_version(value: &serde_json::Value) -> bool {
    matches!(value.get("version"), Some(serde_json::Value::String(v))
        if v == SerializedThreadV0_1_0::VERSION || v == SerializedThread::VERSION)
}

Try / catch

match SerializedThread::from_json(&bytes) {
    Err(e) if e.to_string().contains("unrecognized serialized thread version") => {
        // skip this record; report version to the user instead of failing the whole load
    }
    rest => rest,
}

Prevention

When it happens

Trigger: Loading a thread JSON written by a newer Zed (version `"0.3.0"`+), a hand-edited `version` string, or a file that is not a thread document but happens to contain a `version` string field.

Common situations: Downgrading Zed after threads were saved by a newer version; opening a thread DB from another machine running newer Zed; schema-version constants drifting between forks/branches of the codebase.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/9272a4beb60cd938. Report an issue: GitHub.