flxzt/rnote · error · anyhow::Error

shapestroke does not contain 'shape'.

Error message

shapestroke does not contain 'shape'.

What it means

Thrown in TryFrom::<RnoteFileMaj0Min13>::try_from during the maj0min13->maj0min15 migration. A component's 'value.shapestroke' object must contain a 'shape' key describing the geometry (rect or ellipse) whose transform is converted; when 'shape' is absent, the migration fails. This indicates shape-stroke data that does not conform to the v0.13 schema.

Solutions

  1. Add the missing 'shape' object (with a 'rect' or 'ellipse' entry) to the shapestroke payload.
  2. Re-save the file with the originating Rnote version so the schema is correct, then retry.
  3. Restore the file from a backup or Rnote's autosave.
  4. If the component is unsalvageable, set its 'value' to null so migration skips it.

Example fix

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

Strategy: validation

Validate before calling

fn shapestroke_has_shape(comp: &serde_json::Value) -> bool {
    comp.get("value")
        .and_then(|v| v.get("shapestroke"))
        .and_then(|s| s.get("shape"))
        .is_some()
}

Type guard

fn get_shape<'a>(shapestroke: &'a serde_json::Value) -> Option<&'a serde_json::Value> {
    shapestroke.get("shape")
}

Try / catch

match RnoteFileMaj0Min15::try_from(file) {
    Ok(f) => open(f),
    Err(e) if e.to_string().contains("does not contain 'shape'") => {
        log::error!("shapestroke missing geometry: {e}");
        offer_file_repair_or_restore();
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: try_from hits a component where value['shapestroke'] is an object but has no 'shape' key (e.g. it was renamed to 'geometry' or dropped).

Common situations: Files edited by hand or by third-party tools that renamed/dropped the 'shape' field, or corruption in the stroke component payload.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

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

        {
            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()
                    .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")

View on GitHub (pinned to bbc5354502)