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
- Add the missing 'shape' object (with a 'rect' or 'ellipse' entry) to the shapestroke payload.
- Re-save the file with the originating Rnote version so the schema is correct, then retry.
- Restore the file from a backup or Rnote's autosave.
- 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
- Verify shapestroke objects always carry a 'shape' key before migrating.
- Never rename schema keys ('shape', 'value') in .rnote JSON.
- Keep pre-migration backups of documents.
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
- stroke component does not contain 'value'.
- vectorimage does not contain 'rectangle'.
- document has no value `layout`.
- engine snapshot does not contain 'stroke_components'.
- value is not a JSON object.
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)