flxzt/rnote · error · anyhow::Error

stroke component is not a JSON object.

Error message

stroke component is not a JSON object.

What it means

Thrown when an element of the `stroke_components` array is not a JSON object. Each component must be an object containing a `value` key that the migration can transform; scalar/array elements cannot be processed.

Solutions

  1. Inspect the stroke_components array in the .rnote JSON and remove/repair the malformed element
  2. Re-export the document from the rnote version that created it
  3. In code, skip or default elements that are not objects instead of aborting the whole migration

Example fix

// before
let value = comp
    .as_object_mut()
    .ok_or(anyhow!("stroke component is not a JSON object."))?;
// after
let Some(comp_obj) = comp.as_object_mut() else {
    log::warn!("skipping non-object stroke component");
    continue;
};
let value = comp_obj
    .get_mut("value")
    .ok_or(anyhow!("stroke component does not contain 'value'."))?;
Defensive patterns

Strategy: validation

Validate before calling

let all_objects = engine_snapshot["stroke_components"]
    .as_array()
    .map(|a| a.iter().all(|c| c.as_object().is_some()))
    .unwrap_or(false);
if !all_objects {
    return Err(anyhow!("every stroke component must be a JSON object"));
}

Type guard

fn components_are_objects(snapshot: &ijson::IObject) -> bool {
    snapshot.get("stroke_components")
        .and_then(|v| v.as_array())
        .map(|a| a.iter().all(|c| c.as_object().is_some()))
        .unwrap_or(false)
}

Try / catch

// catch and report the index of the bad component after repair tooling
let file = RnoteFileMaj0Min15::try_from(file_maj0min13)
    .map_err(|e| anyhow!("malformed stroke component while migrating: {e:#}"))?;

Prevention

When it happens

Trigger: Iterating stroke components during the maj0min13 -> maj0min15 conversion when one array element is a non-object JSON value — e.g. null, a string, or a nested array from a corrupt or malformed file.

Common situations: Damaged .rnote archives with partially written component arrays; hand-edited JSON; fixtures generated by other tooling with the wrong component shape.

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/7528a1dba4d8789c. Report an issue: GitHub.

Appendix: source

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

    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."))?
                    .get_mut("shape")
                    .ok_or(anyhow!("shapestroke does not contain 'shape'."))?;

                if let Some(rect) = shape
                    .as_object_mut()

View on GitHub (pinned to bbc5354502)