{"record":{"id":"d61d41d104beea23","repo":"flxzt/rnote","slug":"store-snapshot-is-not-a-json-object","errorCode":null,"errorMessage":"store snapshot is not a JSON object.","messagePattern":"store snapshot is not a JSON object\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/rnoteformat/maj0min6.rs","lineNumber":22,"sourceCode":"use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct RnoteFileMaj0Min6 {\n    /// A snapshot of the engine.\n    #[serde(rename = \"engine_snapshot\")]\n    pub engine_snapshot: ijson::IValue,\n}\n\nimpl TryFrom<RnoteFileMaj0Min5Patch9> for RnoteFileMaj0Min6 {\n    type Error = anyhow::Error;\n\n    fn try_from(mut value: RnoteFileMaj0Min5Patch9) -> Result<Self, Self::Error> {\n        let mut engine_snapshot = ijson::IObject::new();\n\n        let store_snapshot = value\n            .store_snapshot\n            .as_object_mut()\n            .ok_or_else(|| anyhow!(\"store snapshot is not a JSON object.\"))?;\n\n        engine_snapshot.insert(String::from(\"document\"), value.document);\n        engine_snapshot.insert(\n            String::from(\"stroke_components\"),\n            store_snapshot\n                .remove(\"stroke_components\")\n                .ok_or_else(|| anyhow!(\"store snapshot has no value `stroke_components`.\"))?,\n        );\n        engine_snapshot.insert(\n            String::from(\"chrono_components\"),\n            store_snapshot\n                .remove(\"chrono_components\")\n                .ok_or_else(|| anyhow!(\"store snapshot has no value `chrono_components`.\"))?,\n        );\n        engine_snapshot.insert(\n            String::from(\"chrono_counter\"),\n            store_snapshot\n                .remove(\"chrono_counter\")","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/rnoteformat/maj0min6.rs#L4-L40","documentation":"During the maj0min5patch9 -> maj0min6 rnote file migration, the file's `store_snapshot` must be a JSON object because the migration needs to move its keys (`stroke_components`, `chrono_components`, `chrono_counter`) into the new top-level `engine_snapshot`. This error is thrown when `store_snapshot` is a non-object JSON value.","triggerScenarios":"Calling `RnoteFileMaj0Min6::try_from(RnoteFileMaj0Min5Patch9)` on a file whose `store_snapshot` field is a string, array, number, or other non-object JSON value.","commonSituations":"Corrupted or partially written .rnote files; manual edits that replaced the store snapshot object with a scalar value.","solutions":["Unzip the .rnote file and confirm `store_snapshot` is a JSON object containing `stroke_components`, `chrono_components`, and `chrono_counter`.","Restore the file from a backup or autosave copy.","Re-save the document with the rnote version matching its stored format version.","If editing manually, restructure the file as `{ \"store_snapshot\": { ... }, \"document\": {...} }`."],"exampleFix":"// before\n\"store_snapshot\": \"corrupted\"\n// after\n\"store_snapshot\": { \"stroke_components\": [], \"chrono_components\": [], \"chrono_counter\": 0 }","handlingStrategy":"type-guard","validationCode":"// validate before migration\nfn store_snapshot_is_object(doc: &serde_json::Value) -> bool {\n    doc.get(\"store_snapshot\").map_or(false, |s| s.is_object())\n}","typeGuard":"fn store_snapshot_object(doc: &serde_json::Value) -> Option<&serde_json::Map<String, serde_json::Value>> {\n    doc.get(\"store_snapshot\")?.as_object()\n}","tryCatchPattern":"match RnoteFileMaj0Min6::try_from(prev) {\n    Ok(migrated) => /* use migrated */,\n    Err(e) if e.to_string().contains(\"store snapshot is not a JSON object\") => {\n        // restore `store_snapshot` object from backup or rebuild defaults\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always keep `store_snapshot` as a JSON object in maj0min5patch9 files.","Validate the file structure before upgrading versions.","Keep backups before running migrations.","Upgrade through official rnote save/load paths, not raw JSON edits."],"tags":["file-format","json","migration","type-mismatch"],"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"}