{"record":{"id":"20b32e014e58605f","repo":"flxzt/rnote","slug":"shape-is-not-a-json-object","errorCode":null,"errorMessage":"shape is not a JSON object.","messagePattern":"shape is not a JSON object\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs","lineNumber":53,"sourceCode":"                .get_mut(\"value\")\n                .ok_or(anyhow!(\"stroke component does not contain 'value'.\"))?;\n            if value.is_null() {\n                continue;\n            }\n            if let Some(shapestroke) = value\n                .as_object_mut()\n                .ok_or(anyhow!(\"value is not a JSON object.\"))?\n                .get_mut(\"shapestroke\")\n            {\n                let shape = shapestroke\n                    .as_object_mut()\n                    .ok_or(anyhow!(\"shapestroke is not a JSON object.\"))?\n                    .get_mut(\"shape\")\n                    .ok_or(anyhow!(\"shapestroke does not contain 'shape'.\"))?;\n\n                if let Some(rect) = shape\n                    .as_object_mut()\n                    .ok_or(anyhow!(\"shape is not a JSON object.\"))?\n                    .get_mut(\"rect\")\n                {\n                    convert_transform_to_affine_in_obj(rect)?;\n                } else if let Some(ellipse) = shape\n                    .as_object_mut()\n                    .ok_or(anyhow!(\"shape is not a JSON object.\"))?\n                    .get_mut(\"ellipse\")\n                {\n                    convert_transform_to_affine_in_obj(ellipse)?;\n                }\n            } else if let Some(textstroke) = value\n                .as_object_mut()\n                .ok_or(anyhow!(\"value is not a JSON object.\"))?\n                .get_mut(\"textstroke\")\n            {\n                convert_transform_to_affine_in_obj(textstroke)?;\n            } else if let Some(vectorimage) = value\n                .as_object_mut()","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs#L35-L71","documentation":"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.","triggerScenarios":"try_from hits a component where value.shapestroke['shape'] exists but is not a JSON object, e.g. shape: \"rect\" or shape: 3.","commonSituations":"Hand-edited archives where the shape enum object was flattened to a string, corruption from partial writes, or files from a non-Rnote tool.","solutions":["Repair the JSON so 'shape' is an object with a 'rect' or 'ellipse' key.","Re-save the file in the Rnote version that wrote it, then retry migration.","Restore from backup/autosave instead of editing the archive manually.","Set the component's 'value' to null if it cannot be repaired, so the migration skips it."],"exampleFix":"// before\n{\"shape\": \"rect\"}\n// after\n{\"shape\": {\"rect\": {\"transform\": {\"affine\": [1,0,0,1,0,0,0,0,1]}}}}","handlingStrategy":"validation","validationCode":"fn shape_is_object(shapestroke: &serde_json::Value) -> bool {\n    shapestroke.get(\"shape\").map_or(false, |s| s.is_object())\n}","typeGuard":"fn as_shape_object<'a>(shapestroke: &'a serde_json::Value) -> Option<&'a serde_json::Map<String, serde_json::Value>> {\n    shapestroke.get(\"shape\").and_then(|s| s.as_object())\n}","tryCatchPattern":"match RnoteFileMaj0Min15::try_from(file) {\n    Ok(f) => open(f),\n    Err(e) if e.to_string().contains(\"shape is not a JSON object\") => {\n        log::error!(\"shape geometry has wrong type: {e}\");\n        restore_from_backup();\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Assert shape is an object with a rect/ellipse key before migration.","Do not serialize shape variants as scalars or strings.","Round-trip files through Rnote to normalize the schema after external edits."],"tags":["json","migration","type-mismatch","file-format"],"backgroundTag":"type-mismatch","analyzedSha":"bbc5354502ba2fc83eec2670b535348825e679a6","analyzedAt":"2026-09-08T13:20:33.747Z","contentChangedAt":"2026-09-08T13:20:33.747Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}