flxzt/rnote · error · anyhow::Error
value is not a JSON object.
Error message
value is not a JSON object.
What it means
Thrown in TryFrom::<RnoteFileMaj0Min13>::try_from during the maj0min13->maj0min15 migration. After fetching the component's 'value', the code must treat it as a JSON object to look up stroke kinds like 'shapestroke'; if 'value' is a non-object (string, number, array, bool), migration fails. A null 'value' is tolerated and skipped, so this only fires for non-null non-objects.
Solutions
- Re-save the file with the original Rnote version so 'value' is serialized as a proper object.
- Inspect and repair the JSON: make each non-null component 'value' a JSON object with a kind key (shapestroke/textstroke/vectorimage/bitmapimage).
- Restore the file from backup/autosave instead of hand-editing.
- If the value is unfixable junk, replace it with null — null components are skipped by the migration.
Example fix
// before
{"value": "shapestroke-data"}
// after
{"value": {"shapestroke": {"shape": {"rect": {"transform": {...}}}}}} Defensive patterns
Strategy: validation
Validate before calling
fn value_is_object_or_null(comp: &serde_json::Value) -> bool {
comp.get("value").map_or(false, |v| v.is_object() || v.is_null())
} Type guard
fn as_value_object<'a>(comp: &'a serde_json::Value) -> Option<&'a serde_json::Map<String, serde_json::Value>> {
comp.get("value").and_then(|v| v.as_object())
} Try / catch
match RnoteFileMaj0Min15::try_from(file) {
Ok(f) => open(f),
Err(e) if e.to_string().contains("value is not a JSON object") => {
log::error!("stroke component value has wrong type: {e}");
fallback_to_read_only_or_backup();
}
Err(e) => return Err(e),
} Prevention
- Validate each stroke component's 'value' is an object or null before migration.
- Avoid third-party tools that rewrite .rnote internals; re-export via Rnote.
- Checksum/backup files before any manual repair attempt.
When it happens
Trigger: try_from encounters a stroke component whose 'value' is present and non-null but is not a JSON object, e.g. value: "stroke" or value: [1,2].
Common situations: Corrupted or externally edited .rnote files, or files written by a tool that serialized the component value as a scalar/array instead of an object.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- shapestroke is not a JSON object.
- shape is not a JSON object.
- vectorimage is not a JSON object.
- stroke value is not a JSON Object.
- brushstroke is not a JSON object.
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/b2703f983647a5b0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/fileformats/rnoteformat/maj0min15.rs:42
.get_mut("stroke_components")
.ok_or(anyhow!(
"engine snapshot does not contain 'stroke_components'."
))?
.as_array_mut()
.ok_or(anyhow!("stroke components is not a JSON array."))?
.iter_mut()
{
let value = comp
.as_object_mut()
.ok_or(anyhow!("stroke component is not a JSON object."))?
.get_mut("value")
.ok_or(anyhow!("stroke component does not contain 'value'."))?;
if value.is_null() {
continue;
}
if let Some(shapestroke) = value
.as_object_mut()
.ok_or(anyhow!("value is not a JSON object."))?
.get_mut("shapestroke")
{
let shape = shapestroke
.as_object_mut()
.ok_or(anyhow!("shapestroke is not a JSON object."))?
.get_mut("shape")
.ok_or(anyhow!("shapestroke does not contain 'shape'."))?;
if let Some(rect) = shape
.as_object_mut()
.ok_or(anyhow!("shape is not a JSON object."))?
.get_mut("rect")
{
convert_transform_to_affine_in_obj(rect)?;
} else if let Some(ellipse) = shape
.as_object_mut()
.ok_or(anyhow!("shape is not a JSON object."))?
.get_mut("ellipse")View on GitHub (pinned to bbc5354502)