linera-io/linera-protocol · error · std::io::Error

failed to parse SNAP body in {path:?} as Formats: {e}

Error message

failed to parse SNAP body in {path:?} as Formats: {e}

What it means

After stripping the frontmatter, load_formats_from_snap deserializes the remaining YAML body into linera_sdk::formats::Formats with serde_yaml_08. This error means the delimiters were fine but the YAML inside is either syntactically invalid or does not match the Formats schema (wrong field names, wrong types, missing required fields). The message includes the path and serde_yaml's parse/deserialize cause.

Source

Thrown at linera-client/src/client_context.rs:971

/// Reads an insta SNAP file containing a YAML-encoded `Formats` value and parses
/// it. The caller BCS-serializes the result to obtain the application formats
/// blob payload: BCS matches the documented intent (the blob is "the BCS
/// serialization of an application's `Formats`") and the encoding the explorer
/// decodes with.
#[cfg(feature = "fs")]
fn load_formats_from_snap(path: &std::path::Path) -> Result<linera_sdk::formats::Formats, Error> {
    let content = fs::read_to_string(path).map_err(|e| {
        std::io::Error::new(e.kind(), format!("failed to read SNAP file {path:?}: {e}"))
    })?;
    let body = strip_snap_frontmatter(&content).ok_or_else(|| {
        std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!("SNAP file {path:?} is missing the `---` frontmatter delimiters"),
        )
    })?;
    let formats = serde_yaml_08::from_str(body).map_err(|e| {
        std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!("failed to parse SNAP body in {path:?} as Formats: {e}"),
        )
    })?;
    Ok(formats)
}

#[cfg(feature = "fs")]
fn strip_snap_frontmatter(content: &str) -> Option<&str> {
    let rest = content.strip_prefix("---\n")?;
    let end = rest.find("\n---\n")?;
    Some(&rest[end + "\n---\n".len()..])
}

#[cfg(not(web))]
impl<Env: Environment> ClientContext<Env> {
    /// Prepares the chains and fungible tokens needed to run a benchmark.
    pub async fn prepare_for_benchmark(

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Read the {e} cause in the message: a scan error points at a line/column to fix (tabs -> spaces, stray quote); a deserialize error names the offending field — rename or retype it to match Formats.
  2. Regenerate the snapshot with the linera-version you are publishing from (run the application's tests with that toolchain) so the body matches the current Formats schema, instead of hand-patching an old .snap.
  3. If you must edit, validate with serde_yaml 0.8 semantics (plain YAML 1.1/1.2 basics, LF, two-space indent) and compare field-for-field against a known-good snapshot in the same repo.

Example fix

# before (body inside the snap; breaks on tab indent / unknown field)
---
source: format.rs
---
	formats:   # tab indentation -> YAML scan error

# after
---
source: format.rs
---
formats:
  - ...
Defensive patterns

Strategy: validation

Validate before calling

fn snap_body_parses(content: &str) -> bool {
    let rest = content.strip_prefix("---\n")?;
    let end = rest.find("\n---\n")?;
    serde_yaml_08::from_str::<linera_sdk::formats::Formats>(&rest[end + 5..]).is_ok()
}
// (make it return bool by mapping Option->false in the caller)

Type guard

fn is_parsable_formats(yaml_body: &str) -> bool {
    serde_yaml_08::from_str::<serde_yaml_08::Value>(yaml_body).is_ok()
}

Try / catch

match load_formats_from_snap(path) {
    Ok(f) => f,
    Err(e) if e.to_string().contains("failed to parse SNAP body") => {
        anyhow::bail!("SNAP {path:?} body is not a valid Formats YAML: {e}; regenerate the snapshot")
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Passing --formats a .snap whose body is not valid YAML (tabs for indentation, a stray quote or colon, duplicated keys), or valid YAML that does not deserialize as Formats (renamed/removed fields, wrong nesting, a value of the wrong type for a version/encoding field). It fires after the frontmatter check succeeded.

Common situations: Editing a generated .snap by hand and breaking indentation; snapshots produced by an older/newer linera-version of Formats whose schema changed (field renames, added required entries); copying only part of a snapshot; merging snapshots with duplicate keys; YAML gotchas like unquoted strings starting with special characters or tabs pasted from a browser.

Understand the failure class

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/bdf51e12da29bb5b. Report an issue: GitHub.