flxzt/rnote · error
store snapshot has no value `stroke_components`.
Error message
store snapshot has no value `stroke_components`.
What it means
The maj0min5patch9 -> maj0min6 migration requires `store_snapshot.stroke_components` to exist, since it becomes the top-level `engine_snapshot.stroke_components` in the new format. This error is thrown when the store snapshot object does not contain a `stroke_components` key.
Solutions
- Inspect the extracted file JSON and add a `stroke_components` array (possibly empty) to the store snapshot.
- Restore the document from a backup or autosave.
- Open the file with the rnote version matching the stored format version and re-save it.
- If the key is genuinely obsolete in your file lineage, pre-migrate by inserting an empty `stroke_components` array before conversion.
Example fix
// before
"store_snapshot": { "chrono_components": [] }
// after
"store_snapshot": { "stroke_components": [], "chrono_components": [] } Defensive patterns
Strategy: validation
Validate before calling
// validate before migration
fn has_stroke_components(doc: &serde_json::Value) -> bool {
doc["store_snapshot"].get("stroke_components").map_or(false, |v| v.is_array())
} Type guard
fn store_snapshot_has(doc: &serde_json::Value, key: &str) -> bool {
doc["store_snapshot"].get(key).is_some()
} Try / catch
match RnoteFileMaj0Min6::try_from(prev) {
Ok(migrated) => /* use migrated */,
Err(e) if e.to_string().contains("no value `stroke_components`") => {
// insert an empty stroke_components array and retry
}
Err(e) => return Err(e),
} Prevention
- Ensure store snapshots always carry `stroke_components`, even if empty.
- Validate required store snapshot keys before migration.
- Keep backups/autosaves of .rnote files.
- Migrate through the rnote app rather than hand-editing file JSON.
When it happens
Trigger: Running `RnoteFileMaj0Min6::try_from` on a file whose store snapshot object lacks `stroke_components` after the `remove()` call.
Common situations: Files written by an older rnote build that predates stroke_components, hand-edited files with the key removed, or corruption during save.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- brushstroke has no value `path`.
- store snapshot has no value `chrono_components`.
- store snapshot has no value `chrono_counter`.
- document has no value `layout`.
- engine snapshot does not contain 'stroke_components'.
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/ef86bf0b3b7a60c5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min6.rs:29
}
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")
.ok_or_else(|| anyhow!("store snapshot has no value `chrono_counter`."))?,
);
Ok(Self {
engine_snapshot: engine_snapshot.into(),
})
}View on GitHub (pinned to bbc5354502)