{"record":{"id":"50d63a0404cc4a7c","repo":"flxzt/rnote","slug":"failed-to-parse-left-attribute-in-xopptext-with","errorCode":null,"errorMessage":"failed to parse `left` attribute in XoppText with node id {:?}, could not find attribute","messagePattern":"failed to parse `left` attribute in XoppText with node id (.+?), could not find attribute","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/fileformats/xoppformat.rs","lineNumber":957,"sourceCode":"    /// The left x position.\n    pub left: f64,\n    /// The top y position.\n    pub top: f64,\n    /// The right x position.\n    pub right: f64,\n    /// The bottom y position.\n    pub bottom: f64,\n    /// The image data encoded as Png base64.\n    pub data: String,\n}\n\nimpl XmlLoadable for XoppImage {\n    fn load_from_xml(&mut self, node: Node) -> anyhow::Result<()> {\n        // Left\n        self.left = node\n            .attribute(\"left\")\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"failed to parse `left` attribute in XoppText with node id {:?}, could not find attribute\",\n                    node.id()\n                )\n            })?\n            .parse::<f64>()?;\n\n        // Top\n        self.top = node\n            .attribute(\"top\")\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"failed to parse `top` attribute in XoppText with node id {:?}, could not find attribute\",\n                    node.id()\n                )\n            })?\n            .parse::<f64>()?;\n\n        // Right","sourceCodeStart":939,"sourceCodeEnd":975,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/fileformats/xoppformat.rs#L939-L975","documentation":"Thrown by XoppImage::load_from_xml when an `<image>` element has no `left` attribute. The left offset is parsed as f64 to position the image; its absence aborts parsing. Note the message says \"XoppText\" — it is a copy-paste mislabel in rnote's source; the actual element being parsed is XoppImage.","triggerScenarios":"Importing a .xopp file whose <image> element lacks the `left` attribute — files generated by external tools, hand-edited XML, or corrupted files missing position attributes (left/right/top/bottom).","commonSituations":"Custom xopp producers omitting image coordinates; manual XML edits; partial writes dropping attributes; confusion caused by the misleading 'XoppText' wording in the message while debugging image elements.","solutions":["Add a left attribute to the <image> element, e.g. left=\"0.0\" (and ensure right/top/bottom are also present).","Regenerate the file with all four position attributes on every <image> element.","Open and re-save the file in Xournal++ to write canonical image attributes, then re-import."],"exampleFix":"// before (file XML)\n<image right=\"200\" top=\"0\" bottom=\"100\">...</image>\n// after (file XML)\n<image left=\"0\" right=\"200\" top=\"0\" bottom=\"100\">...</image>","handlingStrategy":"validation","validationCode":"fn image_has_position_attrs(xml: &str) -> Result<(), String> {\n    const REQ: [&str; 4] = [\"left=\", \"right=\", \"top=\", \"bottom=\"];\n    for (i, chunk) in xml.split(\"<image\").skip(1).enumerate() {\n        let head = chunk.split('>').next().unwrap_or(\"\");\n        for r in REQ {\n            if !head.contains(r) {\n                return Err(format!(\"image #{i} missing attribute {}\", r.trim_end_matches('=')));\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"fn image_attrs_ok(attrs: &[(&str, &str)]) -> bool {\n    [\"left\", \"right\", \"top\", \"bottom\"]\n        .iter()\n        .all(|req| attrs.iter().any(|(k, _)| k == req))\n}","tryCatchPattern":"match import_xopp(path) {\n    Err(e) if e.to_string().contains(\"`left` attribute in XoppText\") => {\n        // note: message mislabels XoppImage as XoppText; still fix the <image> element\n        eprintln!(\"An <image> element is missing position attributes (left/right/top/bottom): {e:#}\");\n    }\n    Err(e) => eprintln!(\"import failed: {e:#}\"),\n    Ok(doc) => { /* proceed */ }\n}","preventionTips":["Always emit all four position attributes (left, right, top, bottom) on <image> elements","Remember this message says 'XoppText' even for images — don't be misled while debugging","Re-save files via Xournal++ if image attributes look incomplete"],"tags":["parsing","xml","missing-attribute","xopp","misleading-error-message"],"backgroundTag":"missing-required-argument","analyzedSha":"bbc5354502ba2fc83eec2670b535348825e679a6","analyzedAt":"2026-09-08T13:20:33.747Z","contentChangedAt":"2026-09-08T13:20:33.747Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}