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

  1. Inspect the failing entry in the extracted file JSON and ensure `stroke_components[i].value` is a JSON object.
  2. Restore the file from a backup or autosave rather than patching by hand.
  3. Re-export or re-save the document with the rnote version matching the file's stored format version.
  4. 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

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


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)