{"record":{"id":"b2703f983647a5b0","repo":"flxzt/rnote","slug":"value-is-not-a-json-object","errorCode":null,"errorMessage":"value is not a JSON object.","messagePattern":"value is not a JSON object\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs","lineNumber":42,"sourceCode":"            .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()\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\")","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs#L24-L60","documentation":"Thrown in TryFrom::<RnoteFileMaj0Min13>::try_from during the maj0min13->maj0min15 migration. After fetching the component's 'value', the code must treat it as a JSON object to look up stroke kinds like 'shapestroke'; if 'value' is a non-object (string, number, array, bool), migration fails. A null 'value' is tolerated and skipped, so this only fires for non-null non-objects.","triggerScenarios":"try_from encounters a stroke component whose 'value' is present and non-null but is not a JSON object, e.g. value: \"stroke\" or value: [1,2].","commonSituations":"Corrupted or externally edited .rnote files, or files written by a tool that serialized the component value as a scalar/array instead of an object.","solutions":["Re-save the file with the original Rnote version so 'value' is serialized as a proper object.","Inspect and repair the JSON: make each non-null component 'value' a JSON object with a kind key (shapestroke/textstroke/vectorimage/bitmapimage).","Restore the file from backup/autosave instead of hand-editing.","If the value is unfixable junk, replace it with null — null components are skipped by the migration."],"exampleFix":"// before\n{\"value\": \"shapestroke-data\"}\n// after\n{\"value\": {\"shapestroke\": {\"shape\": {\"rect\": {\"transform\": {...}}}}}}","handlingStrategy":"validation","validationCode":"fn value_is_object_or_null(comp: &serde_json::Value) -> bool {\n    comp.get(\"value\").map_or(false, |v| v.is_object() || v.is_null())\n}","typeGuard":"fn as_value_object<'a>(comp: &'a serde_json::Value) -> Option<&'a serde_json::Map<String, serde_json::Value>> {\n    comp.get(\"value\").and_then(|v| v.as_object())\n}","tryCatchPattern":"match RnoteFileMaj0Min15::try_from(file) {\n    Ok(f) => open(f),\n    Err(e) if e.to_string().contains(\"value is not a JSON object\") => {\n        log::error!(\"stroke component value has wrong type: {e}\");\n        fallback_to_read_only_or_backup();\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Validate each stroke component's 'value' is an object or null before migration.","Avoid third-party tools that rewrite .rnote internals; re-export via Rnote.","Checksum/backup files before any manual repair attempt."],"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"}