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
- Fix the file JSON so each 'transform' is an object like {"affine": [m00,m01,m02,m10,m11,m12,m20,m21,m22]}.
- Restore the note from a backup and re-save it via the app.
- Fix the generating tool to serialize the legacy Transform as a struct/object.
- 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
- Serialize the legacy Transform via serde so it is always {affine: [9 numbers]}.
- Validate transform shape (object + 9-element affine) before migrating.
- Avoid ad-hoc JSON rewrites that unwrap the transform object.
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
- image is not a JSON object.
- supplied value is not a JSON object.
- bitmapimage is not a JSON object.
- bitmapimage does not contain 'image'.
- image does not contain 'rectangle'.
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)