flxzt/rnote · error · anyhow::Error

shape is not a JSON object.

Error message

shape is not a JSON object.

What it means

Thrown in TryFrom::<RnoteFileMaj0Min13>::try_from during the maj0min13->maj0min15 migration. Once a shapestroke's 'shape' value is found, it must be a JSON object so the code can locate its 'rect' or 'ellipse' variant and convert the transform; if 'shape' is a non-object (scalar/array), migration aborts. It reflects shape geometry stored in an unexpected type.

Solutions

  1. Repair the JSON so 'shape' is an object with a 'rect' or 'ellipse' key.
  2. Re-save the file in the Rnote version that wrote it, then retry migration.
  3. Restore from backup/autosave instead of editing the archive manually.
  4. Set the component's 'value' to null if it cannot be repaired, so the migration skips it.

Example fix

// before
{"shape": "rect"}
// after
{"shape": {"rect": {"transform": {"affine": [1,0,0,1,0,0,0,0,1]}}}}
Defensive patterns

Strategy: validation

Validate before calling

fn shape_is_object(shapestroke: &serde_json::Value) -> bool {
    shapestroke.get("shape").map_or(false, |s| s.is_object())
}

Type guard

fn as_shape_object<'a>(shapestroke: &'a serde_json::Value) -> Option<&'a serde_json::Map<String, serde_json::Value>> {
    shapestroke.get("shape").and_then(|s| s.as_object())
}

Try / catch

match RnoteFileMaj0Min15::try_from(file) {
    Ok(f) => open(f),
    Err(e) if e.to_string().contains("shape is not a JSON object") => {
        log::error!("shape geometry has wrong type: {e}");
        restore_from_backup();
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: try_from hits a component where value.shapestroke['shape'] exists but is not a JSON object, e.g. shape: "rect" or shape: 3.

Common situations: Hand-edited archives where the shape enum object was flattened to a string, corruption from partial writes, or files from a non-Rnote tool.

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/20b32e014e58605f. Report an issue: GitHub.

Appendix: source

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

                .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()
                    .ok_or(anyhow!("shape is not a JSON object."))?
                    .get_mut("rect")
                {
                    convert_transform_to_affine_in_obj(rect)?;
                } else if let Some(ellipse) = shape
                    .as_object_mut()
                    .ok_or(anyhow!("shape is not a JSON object."))?
                    .get_mut("ellipse")
                {
                    convert_transform_to_affine_in_obj(ellipse)?;
                }
            } else if let Some(textstroke) = value
                .as_object_mut()
                .ok_or(anyhow!("value is not a JSON object."))?
                .get_mut("textstroke")
            {
                convert_transform_to_affine_in_obj(textstroke)?;
            } else if let Some(vectorimage) = value
                .as_object_mut()

View on GitHub (pinned to bbc5354502)