flxzt/rnote · error · anyhow::Error
rect does not contain 'transform'.
Error message
rect does not contain 'transform'.
What it means
Thrown in convert_transform_to_affine_in_obj when the supplied object has no 'transform' key. The migration's purpose is to replace the legacy nested transform.affine array with a flat 'affine' array; without 'transform' there is nothing to convert, so the maj0min13 -> maj0min15 upgrade fails. (The message says 'rect' but applies to any object passed to the helper.)
Solutions
- Check whether the node already has a flat 'affine' key (already migrated) and make the migration idempotent: skip conversion if 'transform' is absent but 'affine' exists.
- Restore the original maj0min13 file from a backup and migrate it once, cleanly.
- Re-insert the legacy 'transform' object in the file JSON if the source of truth is known.
- Soften the helper to treat a missing 'transform' as a no-op with a warning instead of an error.
Example fix
// before: hard failure
let transform = obj.remove("transform").ok_or(anyhow!("rect does not contain 'transform'."))?;
// after: idempotent migration
if obj.get("affine").is_some() { return Ok(()); } // already converted
let Some(transform) = obj.remove("transform") else {
log::warn!("no 'transform' to convert; skipping");
return Ok(());
}; Defensive patterns
Strategy: fallback
Validate before calling
if node.get("transform").is_none() && node.get("affine").is_some() {
// already migrated; skip
} Type guard
fn needs_transform_conversion(obj: &IValue) -> bool {
obj.get("transform").is_some() && obj.get("affine").is_none()
} Try / catch
if let Err(e) = convert_transform_to_affine_in_obj(rect) {
if e.to_string().contains("does not contain 'transform'") {
// likely already migrated; continue instead of failing
} else { return Err(e); }
} Prevention
- Make the migration idempotent: skip nodes that already have a flat 'affine'.
- Migrate each file exactly once; mark files with their format version.
- Never run an old-format migration on files already in a newer format.
When it happens
Trigger: Migrating a file where a rectangle/textstroke/shape node exists but lacks the legacy 'transform' object (e.g. already migrated, partially migrated, or never had one).
Common situations: Files that were partially migrated (transform already removed but 'affine' not inserted); hand-edited JSON; nodes created by tools targeting a newer format being run through the old-format migration.
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
- bitmapimage does not contain 'image'.
- image does not contain 'rectangle'.
- bitmapimage does not contain 'rectangle'.
- transform does not contain 'affine'.
- no value `stroke_components` in `store_snapshot`
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/192d878a598d4e7d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs:123
}
}
//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"))?,
affineView on GitHub (pinned to bbc5354502)