flxzt/rnote · error · anyhow::Error

stroke components is not a JSON array.

Error message

stroke components is not a JSON array.

What it means

Thrown when the `stroke_components` entry in the engine snapshot exists but is not a JSON array. The migration iterates the components with `.iter_mut()`, which requires an array, so it validates with `as_array_mut()` first.

Solutions

  1. Unzip the .rnote file and confirm `stroke_components` is a JSON array
  2. Fix the JSON type manually or regenerate the file from the original data
  3. In code, coerce/wrap a non-array value into an array before the migration

Example fix

// before
.as_array_mut()
.ok_or(anyhow!("stroke components is not a JSON array."))?;
// after
match engine_snapshot.get_mut("stroke_components").map(|v| v.as_array_mut()) {
    Some(Some(arr)) => arr,
    _ => return Err(anyhow!("stroke components is not a JSON array.")),
}
Defensive patterns

Strategy: type-guard

Validate before calling

match engine_snapshot.get("stroke_components") {
    Some(v) if v.as_array().is_some() => {},
    _ => return Err(anyhow!("stroke_components must be a JSON array")),
}

Type guard

fn stroke_components_is_array(snapshot: &ijson::IObject) -> bool {
    snapshot.get("stroke_components").and_then(|v| v.as_array()).is_some()
}

Try / catch

// narrow the failing step with context
RnoteFileMaj0Min15::try_from(file_maj0min13)
    .with_context(|| "invalid stroke_components type while migrating .rnote file")?;

Prevention

When it happens

Trigger: Converting an RnoteFileMaj0Min13 whose engine snapshot has `stroke_components` set to an object, string, number, or null instead of an array — usually from corruption or a schema mismatch.

Common situations: Files edited by hand or by scripts that replaced the array with a different JSON type; incompatible snapshots from other tools; truncated writes.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08). Data as JSON: /api/errors/2aa5ce56b652c22e. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs:29

    pub engine_snapshot: ijson::IValue,
}

impl TryFrom<RnoteFileMaj0Min13> for RnoteFileMaj0Min15 {
    type Error = anyhow::Error;

    fn try_from(mut value: RnoteFileMaj0Min13) -> Result<Self, Self::Error> {
        let engine_snapshot = value
            .engine_snapshot
            .as_object_mut()
            .ok_or(anyhow!("engine snapshot is not a JSON object."))?;

        for comp in engine_snapshot
            .get_mut("stroke_components")
            .ok_or(anyhow!(
                "engine snapshot does not contain 'stroke_components'."
            ))?
            .as_array_mut()
            .ok_or(anyhow!("stroke components is not a JSON array."))?
            .iter_mut()
        {
            let value = comp
                .as_object_mut()
                .ok_or(anyhow!("stroke component is not a JSON object."))?
                .get_mut("value")
                .ok_or(anyhow!("stroke component does not contain 'value'."))?;
            if value.is_null() {
                continue;
            }
            if let Some(shapestroke) = value
                .as_object_mut()
                .ok_or(anyhow!("value is not a JSON object."))?
                .get_mut("shapestroke")
            {
                let shape = shapestroke
                    .as_object_mut()
                    .ok_or(anyhow!("shapestroke is not a JSON object."))?

View on GitHub (pinned to bbc5354502)