flxzt/rnote · error

failed to parse `color` attribute in XoppStroke with node id

Error message

failed to parse `color` attribute in XoppStroke with node id {:?}, could not find attribute

What it means

Thrown by XoppStroke::load_from_xml when a `<stroke>` element has no `color` attribute. The parser passes the attribute value to XoppColor::from_strokecolor_attr_value, and it uses ok_or_else to raise this error (with the node id) when the attribute is absent, since a stroke color is mandatory in the XOPP format.

Solutions

  1. Add a color attribute to the stroke element, e.g. color="black" or color="#ff0000ff".
  2. Regenerate the file ensuring every <stroke> element includes color.
  3. Open and re-save the file in Xournal++ to restore required attributes, then re-import.
  4. Validate the XML against the XOPP schema/known attribute set before importing.

Example fix

// before (file XML)
<stroke tool="pen" width="2.26">...</stroke>
// after (file XML)
<stroke tool="pen" width="2.26" color="black">...</stroke>
Defensive patterns

Strategy: validation

Validate before calling

fn stroke_elements_have_color(xml: &str) -> Result<(), String> {
    for (i, chunk) in xml.split("<stroke").skip(1).enumerate() {
        let head = chunk.split('>').next().unwrap_or("");
        if !head.contains("color=") {
            return Err(format!("stroke #{i} missing `color` attribute"));
        }
    }
    Ok(())
}

Type guard

fn stroke_attrs_ok(attrs: &[(&str, &str)]) -> bool {
    attrs.iter().any(|(k, _)| *k == "color")
}

Try / catch

match import_xopp(path) {
    Err(e) if e.to_string().contains("`color` attribute in XoppStroke") => {
        eprintln!("A stroke element is missing its color; fix the XML or re-save in Xournal++: {e:#}");
    }
    Err(e) => eprintln!("import failed: {e:#}"),
    Ok(doc) => { /* proceed */ }
}

Prevention

When it happens

Trigger: Importing a .xopp file whose `<stroke>` element is missing the `color` attribute — typically hand-edited files, scripts generating xopp XML without color, or files edited by non-Xournal++ tools that dropped the attribute.

Common situations: Custom export/generation scripts producing incomplete stroke XML; manual XML edits removing color; corrupted or partially written files.

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


AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08). Data as JSON: /api/errors/820bed6fbe038680. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-engine/src/fileformats/xoppformat.rs:723

                "failed to parse `tool` attribute in XoppStroke with node id {:?}, could not find attribute",
                node.id()
            )
        })? {
            "pen" => {
                self.tool = XoppTool::Pen;
            }
            "highlighter" => {
                self.tool = XoppTool::Highlighter;
            }
            "eraser" => {
                self.tool = XoppTool::Eraser;
            }
            _ => {}
        }

        self.color =
            XoppColor::from_strokecolor_attr_value(node.attribute("color").ok_or_else(|| {
                anyhow::anyhow!(
                    "failed to parse `color` attribute in XoppStroke with node id {:?}, could not find attribute",
                    node.id()
                )
            })?)?;

        self.fill = if let Some(fill) = node.attribute("fill") {
            Some(fill.parse::<i32>()?)
        } else {
            None
        };

        self.width = node
            .attribute("width")
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "failed to parse `width` attribute in XoppStroke with node id {:?}, could not find attribute",
                    node.id()
                )

View on GitHub (pinned to bbc5354502)