flxzt/rnote · error · anyhow::Error

transform is not a JSON object.

Error message

transform is not a JSON object.

What it means

Thrown in convert_transform_to_affine_in_obj when the removed 'transform' value is not a JSON object. The helper reads transform.affine (a 3x3 nalgebra matrix serialized as a 9-element array), so 'transform' must be an object; any other JSON type aborts the maj0min13 -> maj0min15 migration.

Solutions

  1. Fix the file JSON so each 'transform' is an object like {"affine": [m00,m01,m02,m10,m11,m12,m20,m21,m22]}.
  2. Restore the note from a backup and re-save it via the app.
  3. Fix the generating tool to serialize the legacy Transform as a struct/object.
  4. Add a type check in the migration that reports the offending component and skips it.

Example fix

// before
let transform = transform.as_object().ok_or(anyhow!("transform is not a JSON object."))?;
// after: caller-side guard
if !value["transform"].is_object() {
    anyhow::bail!("corrupt file: transform must be an object");
}
Defensive patterns

Strategy: type-guard

Validate before calling

let t = &node["transform"];
if !t.is_object() {
    return Err("transform must be an object with an 'affine' array".into());
}

Type guard

fn is_valid_transform(v: &IValue) -> bool {
    v.get("transform")
        .and_then(|t| t.get("affine"))
        .and_then(|a| a.as_array())
        .map_or(false, |a| a.len() == 9)
}

Prevention

When it happens

Trigger: Migrating a file where a node's 'transform' key holds a non-object value (array, string, number) instead of {"affine": [...9 numbers...]}.

Common situations: Corrupted or hand-edited legacy files; exporters writing transform as a flat array instead of an object wrapper.

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/c3321e287cd5279a. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs:126

        //dbg!(&value);

        Ok(Self {
            engine_snapshot: value.engine_snapshot,
        })
    }
}

/// Converts a "object->transform->nalgebra-affine" to "object->(glamx-)affine"
fn convert_transform_to_affine_in_obj(obj: &mut IValue) -> anyhow::Result<()> {
    let obj = obj
        .as_object_mut()
        .ok_or(anyhow!("supplied value is not a JSON object."))?;
    let transform = obj
        .remove("transform")
        .ok_or(anyhow!("rect does not contain 'transform'."))?;
    let transform = transform
        .as_object()
        .ok_or(anyhow!("transform is not a JSON object."))?;
    let affine = transform
        .get("affine")
        .ok_or(anyhow!("transform does not contain 'affine'."))?
        .as_array()
        .ok_or(anyhow!("affine not an array."))?;

    obj.insert(
        "affine",
        vec![
            #[allow(clippy::get_first)]
            affine
                .get(0)
                .cloned()
                .ok_or(anyhow!("affine does not have value at index 0"))?,
            affine
                .get(1)
                .cloned()
                .ok_or(anyhow!("affine does not have value at index 1"))?,

View on GitHub (pinned to bbc5354502)