flxzt/rnote · error
store snapshot is not a JSON object.
Error message
store snapshot is not a JSON object.
What it means
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.
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": {...} }`.
Example fix
// before
"store_snapshot": "corrupted"
// after
"store_snapshot": { "stroke_components": [], "chrono_components": [], "chrono_counter": 0 } Defensive patterns
Strategy: type-guard
Validate before calling
// validate before migration
fn store_snapshot_is_object(doc: &serde_json::Value) -> bool {
doc.get("store_snapshot").map_or(false, |s| s.is_object())
} Type guard
fn store_snapshot_object(doc: &serde_json::Value) -> Option<&serde_json::Map<String, serde_json::Value>> {
doc.get("store_snapshot")?.as_object()
} Try / catch
match RnoteFileMaj0Min6::try_from(prev) {
Ok(migrated) => /* use migrated */,
Err(e) if e.to_string().contains("store snapshot is not a JSON object") => {
// restore `store_snapshot` object from backup or rebuild defaults
}
Err(e) => return Err(e),
} Prevention
- 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.
When it happens
Trigger: Calling `RnoteFileMaj0Min6::try_from(RnoteFileMaj0Min5Patch9)` on a file whose `store_snapshot` field is a string, array, number, or other non-object JSON value.
Common situations: Corrupted or partially written .rnote files; manual edits that replaced the store snapshot object with a scalar value.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- value is not a JSON object.
- shapestroke is not a JSON object.
- shape is not a JSON object.
- vectorimage is not a JSON object.
- stroke value is not a JSON Object.
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/d61d41d104beea23.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min6.rs:22
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RnoteFileMaj0Min6 {
/// A snapshot of the engine.
#[serde(rename = "engine_snapshot")]
pub engine_snapshot: ijson::IValue,
}
impl TryFrom<RnoteFileMaj0Min5Patch9> for RnoteFileMaj0Min6 {
type Error = anyhow::Error;
fn try_from(mut value: RnoteFileMaj0Min5Patch9) -> Result<Self, Self::Error> {
let mut engine_snapshot = ijson::IObject::new();
let store_snapshot = value
.store_snapshot
.as_object_mut()
.ok_or_else(|| anyhow!("store snapshot is not a JSON object."))?;
engine_snapshot.insert(String::from("document"), value.document);
engine_snapshot.insert(
String::from("stroke_components"),
store_snapshot
.remove("stroke_components")
.ok_or_else(|| anyhow!("store snapshot has no value `stroke_components`."))?,
);
engine_snapshot.insert(
String::from("chrono_components"),
store_snapshot
.remove("chrono_components")
.ok_or_else(|| anyhow!("store snapshot has no value `chrono_components`."))?,
);
engine_snapshot.insert(
String::from("chrono_counter"),
store_snapshot
.remove("chrono_counter")View on GitHub (pinned to bbc5354502)