flxzt/rnote · error
stroke value is not a JSON Object.
Error message
stroke value is not a JSON Object.
What it means
In the maj0min5patch8 -> maj0min5patch9 migration, the inner `value` of a stroke component must itself be a JSON object so that its `brushstroke` key can be inspected. This error is thrown when the unwrapped stroke value is a scalar, string, array, or null-adjacent non-object type instead.
Solutions
- Inspect the failing entry in the extracted file JSON and ensure `stroke_components[i].value` is a JSON object.
- Restore the file from a backup or autosave rather than patching by hand.
- Re-export or re-save the document with the rnote version matching the file's stored format version.
- If a null/empty stroke was intended, remove the element from the array entirely instead of leaving a non-object.
Example fix
// before
{ "value": "not-an-object" }
// after
{ "value": { "brushstroke": { "path": [...] } } } Defensive patterns
Strategy: type-guard
Validate before calling
// validate before migration
fn stroke_values_are_objects(doc: &serde_json::Value) -> bool {
doc["store_snapshot"]["stroke_components"]
.as_array()
.map(|arr| arr.iter().all(|v| v.get("value").map(|x| x.is_object()).unwrap_or(false)))
.unwrap_or(false)
} Type guard
fn stroke_value_is_object(entry: &serde_json::Value) -> bool {
entry.get("value").map(|v| v.is_object()).unwrap_or(false)
} Try / catch
match RnoteFileMaj0Min5Patch9::try_from(file) {
Ok(migrated) => /* use migrated */,
Err(e) if e.to_string().contains("stroke value is not a JSON Object") => {
// skip or repair the offending stroke entry
}
Err(e) => return Err(e),
} Prevention
- Keep the `{ "value": { ... } }` wrapper structure intact when manipulating stroke_components JSON.
- Validate document JSON against the format schema before saving or migrating.
- Prefer programmatic edits via rnote APIs over raw JSON surgery.
- Maintain backups before running format upgrades.
When it happens
Trigger: Running `RnoteFileMaj0Min5Patch9::try_from` on a file where a `stroke_components[i].value` entry is not a JSON object, so `.as_object_mut()` fails while probing for `brushstroke`.
Common situations: Manually edited or corrupted .rnote files where a stroke `value` was replaced with a plain value, or files produced by a tool writing the wrong nesting level.
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.
- brushstroke is not a JSON object.
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/64a45c16bf41f5bc.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min5patch9.rs:45
.as_array_mut()
.ok_or_else(|| anyhow!("value `stroke_components` is not a JSON array."))?;
for value in stroke_components {
let stroke = value
.as_object_mut()
.ok_or_else(|| anyhow!("value in `stroke_components` array is not a JSON Object."))?
.get_mut("value")
.ok_or_else(|| {
anyhow!("no value `value` in JSON object of `stroke_components` array.")
})?;
if stroke.is_null() {
continue;
}
if let Some(brushstroke) = stroke
.as_object_mut()
.ok_or_else(|| anyhow!("stroke value is not a JSON Object."))?
.get_mut("brushstroke")
{
let brushstroke = brushstroke
.as_object_mut()
.ok_or_else(|| anyhow!("brushstroke is not a JSON object."))?;
let path = ijson::from_value::<PenPathMaj0Min5Patch8>(
&brushstroke
.remove("path")
.ok_or_else(|| anyhow!("brushstroke has no value `path`."))?,
)?;
let mut path_upgraded = ijson::IObject::new();
let mut seg_iter = path.inner().into_iter().peekable();
if let Some(start) = seg_iter.peek() {
let start = match start {
SegmentMaj0Min5Patch8::Dot { element } => element,
SegmentMaj0Min5Patch8::Line { start, .. } => start,
SegmentMaj0Min5Patch8::QuadBez { start, .. } => start,View on GitHub (pinned to bbc5354502)