{"record":{"id":"d5077dbe2494d254","repo":"flxzt/rnote","slug":"stroke-component-does-not-contain-value","errorCode":null,"errorMessage":"stroke component does not contain 'value'.","messagePattern":"stroke component does not contain 'value'\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs","lineNumber":36,"sourceCode":"        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()\n                    .ok_or(anyhow!(\"shape is not a JSON object.\"))?\n                    .get_mut(\"rect\")","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs#L18-L54","documentation":"This error is thrown during migration of an Rnote file (maj0min13 -> maj0min15) in TryFrom::try_from while iterating stroke_components of the engine snapshot. Each stroke component must be a JSON object with a 'value' key; when serde_json/ijson deserialization yields a component lacking 'value', the migration aborts. It indicates a malformed or hand-edited .rnote file whose stroke component entries deviate from the expected v0.13 schema.","triggerScenarios":"Calling TryFrom::<RnoteFileMaj0Min13>::try_from (or the file-open migration path) on a snapshot where some element of engine_snapshot['stroke_components'] is a JSON object without a 'value' key.","commonSituations":"Opening an .rnote file produced or modified by an incompatible tool version, a partially written/corrupted file, or a hand-edited file where a stroke component's 'value' field was removed or renamed.","solutions":["Open the .rnote file in the Rnote version that wrote it and re-save/export it, then retry migration.","Inspect the JSON inside the .rnote archive (zip) and check every entry in engine_snapshot.stroke_components for a 'value' key.","Restore the file from a backup or autosave, since the file is likely corrupted or externally modified.","If repairing manually, add the missing 'value' object (or null — null components are skipped) to the offending component."],"exampleFix":"// repairing a hand-edited stroke component in the .rnote JSON\n// before\n{\"type\": \"stroke\", \"brush\": \"...\"}\n// after\n{\"type\": \"stroke\", \"value\": {\"stroke\": \"...\"}, \"brush\": \"...\"}","handlingStrategy":"validation","validationCode":"fn stroke_components_valid(snapshot: &serde_json::Value) -> bool {\n    snapshot.get(\"stroke_components\")\n        .and_then(|v| v.as_array())\n        .map(|arr| arr.iter().all(|c|\n            c.get(\"value\").map_or(false, |v| v.is_object() || v.is_null())))\n        .unwrap_or(false)\n}","typeGuard":"fn has_value_field(comp: &serde_json::Value) -> bool {\n    comp.get(\"value\").is_some()\n}","tryCatchPattern":"match RnoteFileMaj0Min15::try_from(file_maj0min13) {\n    Ok(f) => open(f),\n    Err(e) if e.to_string().contains(\"does not contain 'value'\") => {\n        log::error!(\"corrupt stroke component: {e}\");\n        offer_backup_restore();\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never hand-edit the JSON payload inside .rnote archives; use Rnote itself.","Keep .rnote files backed up before upgrading app versions that migrate formats.","Validate archive JSON against the expected schema before running migrations programmatically."],"tags":["json","migration","schema-validation","file-format"],"backgroundTag":"missing-required-config-field","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"}