{"record":{"id":"e37f2e7e499958e2","repo":"flxzt/rnote","slug":"no-value-value-in-json-object-of-stroke-compone","errorCode":null,"errorMessage":"no value `value` in JSON object of `stroke_components` array.","messagePattern":"no value `value` in JSON object of `stroke_components` array\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/rnoteformat/maj0min5patch9.rs","lineNumber":36,"sourceCode":"\nimpl TryFrom<RnoteFileMaj0Min5Patch8> for RnoteFileMaj0Min5Patch9 {\n    type Error = anyhow::Error;\n\n    fn try_from(mut file: RnoteFileMaj0Min5Patch8) -> Result<RnoteFileMaj0Min5Patch9, Self::Error> {\n        let stroke_components = file\n            .store_snapshot\n            .get_mut(\"stroke_components\")\n            .ok_or_else(|| anyhow!(\"no value `stroke_components` in `store_snapshot`\"))?\n            .as_array_mut()\n            .ok_or_else(|| anyhow!(\"value `stroke_components` is not a JSON array.\"))?;\n\n        for value in stroke_components {\n            let stroke = value\n                .as_object_mut()\n                .ok_or_else(|| anyhow!(\"value in `stroke_components` array is not a JSON Object.\"))?\n                .get_mut(\"value\")\n                .ok_or_else(|| {\n                    anyhow!(\"no value `value` in JSON object of `stroke_components` array.\")\n                })?;\n\n            if stroke.is_null() {\n                continue;\n            }\n\n            if let Some(brushstroke) = stroke\n                .as_object_mut()\n                .ok_or_else(|| anyhow!(\"stroke value is not a JSON Object.\"))?\n                .get_mut(\"brushstroke\")\n            {\n                let brushstroke = brushstroke\n                    .as_object_mut()\n                    .ok_or_else(|| anyhow!(\"brushstroke is not a JSON object.\"))?;\n                let path = ijson::from_value::<PenPathMaj0Min5Patch8>(\n                    &brushstroke\n                        .remove(\"path\")\n                        .ok_or_else(|| anyhow!(\"brushstroke has no value `path`.\"))?,","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/rnoteformat/maj0min5patch9.rs#L18-L54","documentation":"During the maj0min5patch8 -> maj0min5patch9 rnote file format migration, each element of the `stroke_components` JSON array must be an object containing a `value` key. This error is thrown when such an object exists but has no `value` field, so the migration cannot unwrap the inner stroke data.","triggerScenarios":"Calling `RnoteFileMaj0Min5Patch9::try_from` on a file whose `store_snapshot.stroke_components` array contains a JSON object lacking the `value` key; typically a corrupted, hand-edited, or partially written .rnote file.","commonSituations":"Opening an .rnote file that was truncated mid-save, produced by a buggy exporter, or manually edited where the wrapper `{ \"value\": ... }` around each stroke component was dropped.","solutions":["Verify the .rnote file is intact (unzip it and inspect the JSON's stroke_components entries; each must contain `value`).","Recover the file from a backup or autosave copy instead of repairing the corrupt one manually.","If repairing manually, add the `value` key wrapping the stroke payload in each affected stroke_components element.","Check whether the file was written by a different/older rnote version and re-export it with a matching version."],"exampleFix":"// before (corrupt entry)\n{ \"stroke_components\": [ { \"brushstroke\": {...} } ] }\n// after (fixed)\n{ \"stroke_components\": [ { \"value\": { \"brushstroke\": {...} } } ] }","handlingStrategy":"validation","validationCode":"// validate before migration\nfn stroke_components_valid(doc: &serde_json::Value) -> bool {\n    doc[\"store_snapshot\"][\"stroke_components\"]\n        .as_array()\n        .map(|arr| arr.iter().all(|v| v.get(\"value\").is_some()))\n        .unwrap_or(false)\n}","typeGuard":"fn has_value_field(entry: &serde_json::Value) -> bool {\n    entry.is_object() && entry.get(\"value\").is_some()\n}","tryCatchPattern":"match RnoteFileMaj0Min5Patch9::try_from(file) {\n    Ok(migrated) => /* use migrated */,\n    Err(e) if e.to_string().contains(\"stroke_components\") => {\n        // recover from backup or repair JSON structure\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never hand-edit .rnote JSON without checking rnoteformat's expected schema for the file version.","Keep automatic backups/autosave of .rnote documents before any migration.","Reject or quarantine files whose stroke_components entries lack `value` at ingest time.","Test migrations on a copy of the file first."],"tags":["file-format","json","migration","corrupt-file"],"backgroundTag":"schema-validation-failed","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"}