flxzt/rnote · error · anyhow::Error

no value `value` in JSON object of `stroke_components`…

Error message

no value `value` in JSON object of `stroke_components` array.

What it means

During the maj0min5patch8 -> maj0min5patch9 rnote file format migration, each element of the `stroke_components` JSON array must be an object containing a `value` key. This error is thrown when such an object exists but has no `value` field, so the migration cannot unwrap the inner stroke data.

Solutions

  1. Verify the .rnote file is intact (unzip it and inspect the JSON's stroke_components entries; each must contain `value`).
  2. Recover the file from a backup or autosave copy instead of repairing the corrupt one manually.
  3. If repairing manually, add the `value` key wrapping the stroke payload in each affected stroke_components element.
  4. Check whether the file was written by a different/older rnote version and re-export it with a matching version.

Example fix

// before (corrupt entry)
{ "stroke_components": [ { "brushstroke": {...} } ] }
// after (fixed)
{ "stroke_components": [ { "value": { "brushstroke": {...} } } ] }
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn has_value_field(entry: &serde_json::Value) -> bool {
    entry.is_object() && entry.get("value").is_some()
}

Try / catch

match RnoteFileMaj0Min5Patch9::try_from(file) {
    Ok(migrated) => /* use migrated */,
    Err(e) if e.to_string().contains("stroke_components") => {
        // recover from backup or repair JSON structure
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `RnoteFileMaj0Min5Patch9::try_from` on a file whose `store_snapshot.stroke_components` array contains a JSON object lacking the `value` key; typically a corrupted, hand-edited, or partially written .rnote file.

Common situations: Opening an .rnote file that was truncated mid-save, produced by a buggy exporter, or manually edited where the wrapper `{ "value": ... }` around each stroke component was dropped.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

impl TryFrom<RnoteFileMaj0Min5Patch8> for RnoteFileMaj0Min5Patch9 {
    type Error = anyhow::Error;

    fn try_from(mut file: RnoteFileMaj0Min5Patch8) -> Result<RnoteFileMaj0Min5Patch9, Self::Error> {
        let stroke_components = file
            .store_snapshot
            .get_mut("stroke_components")
            .ok_or_else(|| anyhow!("no value `stroke_components` in `store_snapshot`"))?
            .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`."))?,

View on GitHub (pinned to bbc5354502)