{"record":{"id":"7528a1dba4d8789c","repo":"flxzt/rnote","slug":"stroke-component-is-not-a-json-object","errorCode":null,"errorMessage":"stroke component is not a JSON object.","messagePattern":"stroke component is not a JSON object\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs","lineNumber":34,"sourceCode":"\n    fn try_from(mut value: RnoteFileMaj0Min13) -> Result<Self, Self::Error> {\n        let engine_snapshot = value\n            .engine_snapshot\n            .as_object_mut()\n            .ok_or(anyhow!(\"engine snapshot is not a JSON object.\"))?;\n\n        for comp in engine_snapshot\n            .get_mut(\"stroke_components\")\n            .ok_or(anyhow!(\n                \"engine snapshot does not contain 'stroke_components'.\"\n            ))?\n            .as_array_mut()\n            .ok_or(anyhow!(\"stroke components is not a JSON array.\"))?\n            .iter_mut()\n        {\n            let value = comp\n                .as_object_mut()\n                .ok_or(anyhow!(\"stroke component is not a JSON object.\"))?\n                .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()","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"Damaged .rnote archives with partially written component arrays; hand-edited JSON; fixtures generated by other tooling with the wrong component shape.","solutions":["Inspect the stroke_components array in the .rnote JSON and remove/repair the malformed element","Re-export the document from the rnote version that created it","In code, skip or default elements that are not objects instead of aborting the whole migration"],"exampleFix":"// before\nlet value = comp\n    .as_object_mut()\n    .ok_or(anyhow!(\"stroke component is not a JSON object.\"))?;\n// after\nlet Some(comp_obj) = comp.as_object_mut() else {\n    log::warn!(\"skipping non-object stroke component\");\n    continue;\n};\nlet value = comp_obj\n    .get_mut(\"value\")\n    .ok_or(anyhow!(\"stroke component does not contain 'value'.\"))?;","handlingStrategy":"validation","validationCode":"let all_objects = engine_snapshot[\"stroke_components\"]\n    .as_array()\n    .map(|a| a.iter().all(|c| c.as_object().is_some()))\n    .unwrap_or(false);\nif !all_objects {\n    return Err(anyhow!(\"every stroke component must be a JSON object\"));\n}","typeGuard":"fn components_are_objects(snapshot: &ijson::IObject) -> bool {\n    snapshot.get(\"stroke_components\")\n        .and_then(|v| v.as_array())\n        .map(|a| a.iter().all(|c| c.as_object().is_some()))\n        .unwrap_or(false)\n}","tryCatchPattern":"// catch and report the index of the bad component after repair tooling\nlet file = RnoteFileMaj0Min15::try_from(file_maj0min13)\n    .map_err(|e| anyhow!(\"malformed stroke component while migrating: {e:#}\"))?;","preventionTips":["Validate every element of stroke_components is an object before conversion","Skip or quarantine malformed components instead of writing them into the file","Test migrations against truncated/corrupted fixtures"],"tags":["json","type-mismatch","migration","rust"],"backgroundTag":"type-mismatch","analyzedSha":"bbc5354502ba2fc83eec2670b535348825e679a6","analyzedAt":"2026-09-08T13:20:33.747Z","contentChangedAt":"2026-09-08T13:20:33.747Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}