{"record":{"id":"d621d5cccda13e33","repo":"flxzt/rnote","slug":"stroke-has-empty-widths-vector","errorCode":null,"errorMessage":"Stroke has empty widths vector.","messagePattern":"Stroke has empty widths vector\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/strokes/stroke.rs","lineNumber":331,"sourceCode":"        let mut widths: Vec<f64> = stroke\n            .width\n            .into_iter()\n            .map(|w| crate::utils::convert_value_dpi(w, xoppformat::XoppFile::DPI, target_dpi))\n            .collect();\n\n        let coords: Vec<Vector2> = stroke\n            .coords\n            .into_iter()\n            .map(|c| {\n                Vector2::new(\n                    crate::utils::convert_value_dpi(c[0], xoppformat::XoppFile::DPI, target_dpi),\n                    crate::utils::convert_value_dpi(c[1], xoppformat::XoppFile::DPI, target_dpi),\n                )\n            })\n            .collect();\n\n        if widths.is_empty() {\n            return Err(anyhow::anyhow!(\"Stroke has empty widths vector.\"));\n        }\n\n        let mut smooth_options = SmoothOptions::default();\n\n        let layer = match stroke.tool {\n            xoppformat::XoppTool::Pen => {\n                smooth_options.stroke_color = Some(crate::utils::color_from_xopp(stroke.color));\n                StrokeLayer::UserLayer(0)\n            }\n            xoppformat::XoppTool::Highlighter => {\n                let mut color = crate::utils::color_from_xopp(stroke.color);\n                // the highlighter always has alpha 0.5\n                color.a = 0.5;\n\n                smooth_options.stroke_color = Some(color);\n                StrokeLayer::Highlighter\n            }\n            xoppformat::XoppTool::Eraser => {","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/strokes/stroke.rs#L313-L349","documentation":"from_xoppstroke converts an Xournal++ (XOPP) stroke into a BrushStroke. A pen stroke in XOPP carries a per-point widths vector; if it parsed to empty, there is no geometry to build a path from, so the conversion aborts with this error. It indicates a malformed or degenerate stroke in the source file.","triggerScenarios":"Importing a .xopp file where a stroke element has no width entries — e.g. a single-tap pen dot recorded with zero width points, a hand-edited/truncated XML file, or an empty <stroke> element.","commonSituations":"Importing Xournal++ files produced by very old versions or other tools with divergent stroke serialization; corrupted or partially recovered .xopp files after a crash.","solutions":["Fix or regenerate the malformed .xopp file; verify the stroke element has width values for each point","Pre-validate the parsed XoppStroke and skip/warn on empty widths instead of failing the whole import","Give single-point strokes a synthetic width (dot) before conversion","Update rnote / the xopp parser in case the file uses an older XOPP format variant"],"exampleFix":"// before\nlet widths: Vec<f64> = stroke.coords.iter().map(|c| convert(c[1])).collect();\nif widths.is_empty() { return Err(...); }\n// after\nlet widths: Vec<f64> = stroke.coords.iter().map(|c| convert(c[1])).collect();\nlet widths = if widths.is_empty() { vec![fallback_width; stroke.coords.len()] } else { widths };","handlingStrategy":"validation","validationCode":"let widths: Vec<f64> = stroke.coords.iter().map(|c| convert_value_dpi(c[1], DPI, target_dpi)).collect();\nif widths.is_empty() {\n    eprintln!(\"skipping degenerate xopp stroke with no widths\");\n    return Ok(None); // skip instead of failing the import\n}","typeGuard":"fn has_widths(s: &XoppStroke) -> bool {\n    !s.coords.is_empty() && s.coords.len() == s.coords.iter().filter(|_| true).count() && !s.coords.is_empty()\n}","tryCatchPattern":"match Stroke::from_xoppstroke(stroke, offset, target_dpi) {\n    Ok(s) => Some(s),\n    Err(e) if e.to_string().contains(\"empty widths\") => {\n        log::warn!(\"degenerate stroke skipped: {e}\");\n        None\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Validate .xopp files (each point has a matching width) before import","Skip-and-log degenerate strokes instead of failing the whole document import","Guard against hand-edited or crash-truncated XOPP files with an XML schema check","Test the importer against XOPP files from multiple Xournal++ versions"],"tags":["xopp","import","empty-vector","stroke"],"backgroundTag":"empty-required-field","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"}