flxzt/rnote · error

brushstroke has no value `path`.

Error message

brushstroke has no value `path`.

What it means

In the maj0min5patch8 -> maj0min5patch9 migration, a `brushstroke` object must contain a `path` key, which holds the pen path to be upgraded to the new segmented format. This error is thrown when the brushstroke object exists but `path` is missing after `remove("path")` returns None.

Solutions

  1. Inspect the file JSON and ensure every brushstroke object includes a `path` array.
  2. Restore the document from a backup or autosave.
  3. If the path is unrecoverable, delete that stroke component from the array so the rest of the file loads.
  4. Re-export the document with the matching rnote version to regenerate a valid brushstroke.

Example fix

// before
{ "brushstroke": { "style": {...} } }
// after
{ "brushstroke": { "path": [], "style": {...} } }
Defensive patterns

Strategy: validation

Validate before calling

// validate before migration
fn brushstrokes_have_path(doc: &serde_json::Value) -> bool {
    doc["store_snapshot"]["stroke_components"]
        .as_array()
        .map(|arr| arr.iter().all(|v|
            v["value"].get("brushstroke").map_or(true, |b| b.get("path").is_some())))
        .unwrap_or(false)
}

Type guard

fn brushstroke_has_path(entry: &serde_json::Value) -> bool {
    entry["value"]["brushstroke"]["path"].is_array()
}

Try / catch

match RnoteFileMaj0Min5Patch9::try_from(file) {
    Ok(migrated) => /* use migrated */,
    Err(e) if e.to_string().contains("brushstroke has no value `path`") => {
        // remove the stroke or restore path from backup
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Running `RnoteFileMaj0Min5Patch9::try_from` on a file where `stroke_components[i].value.brushstroke` is an object but lacks the `path` field.

Common situations: Files truncated or corrupted during write, files edited by hand with the path stripped, or files from a fork that stored geometry under a different key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08). Data as JSON: /api/errors/776752df4b31da31. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min5patch9.rs:54

                    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,
                        SegmentMaj0Min5Patch8::CubBez { start, .. } => start,
                    };
                    path_upgraded.insert(String::from("start"), ijson::to_value(start)?);
                    let mut segments_upgraded = ijson::IArray::new();

                    for seg in seg_iter {
                        let mut segment_upgraded = ijson::IObject::new();

                        match seg {

View on GitHub (pinned to bbc5354502)