{"record":{"id":"56ed9cc3b973c45b","repo":"flxzt/rnote","slug":"could-not-generate-pen-path-from-coordinates-vecto","errorCode":null,"errorMessage":"Could not generate pen path from coordinates vector","messagePattern":"Could not generate pen path from coordinates vector","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rnote-engine/src/strokes/stroke.rs","lineNumber":382,"sourceCode":"\n            // the coordinate widths are relative to the max width\n            widths\n                .iter_mut()\n                .for_each(|coord_width| *coord_width /= max_width);\n        } else {\n            // If there are no coordinate widths, we fill the widths vector with pressure 1.0 for a constant width stroke.\n            widths = (0..coords.len()).map(|_| 1.0).collect();\n        };\n\n        smooth_options.stroke_width = stroke_width;\n\n        let penpath = PenPath::try_from_elements(\n            coords\n                .into_iter()\n                .zip(widths)\n                .map(|(pos, pressure)| Element::new(pos + offset, pressure)),\n        )\n        .ok_or_else(|| anyhow::anyhow!(\"Could not generate pen path from coordinates vector\"))?;\n\n        let brushstroke = BrushStroke::from_penpath(penpath, Style::Smooth(smooth_options));\n\n        Ok((Stroke::BrushStroke(brushstroke), layer))\n    }\n\n    pub fn from_xoppimage(\n        xopp_image: xoppformat::XoppImage,\n        offset: Vector2,\n        target_dpi: f64,\n    ) -> Result<Self, anyhow::Error> {\n        let bounds = Aabb::new(\n            Vector2::new(\n                crate::utils::convert_value_dpi(\n                    xopp_image.left,\n                    xoppformat::XoppFile::DPI,\n                    target_dpi,\n                ),","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/flxzt/rnote/blob/bbc5354502ba2fc83eec2670b535348825e679a6/crates/rnote-engine/src/strokes/stroke.rs#L364-L400","documentation":"After converting XOPP coordinates and widths into Elements, PenPath::try_from_elements returns None when the iterator yields no valid elements (or the widths were empty, causing zip to produce nothing). The function surfaces this as an anyhow error rather than silently producing an empty stroke.","triggerScenarios":"from_xoppstroke called with a stroke whose coords/widths are empty or mismatched in length (zip truncates to the shorter), leaving try_from_elements with zero elements.","commonSituations":"Importing degenerate or empty <stroke> entries from a .xopp file; mismatched coordinate/width counts after a parser bug or hand-edited file.","solutions":["Check that coords.len() == widths.len() and both are non-empty before conversion","Skip or log-and-continue for strokes with zero points during XOPP import","Inspect the .xopp file's stroke element for missing width or position data","If widths were repaired (e.g. from error 141), verify the repair produces one width per coordinate"],"exampleFix":"// before\nlet penpath = PenPath::try_from_elements(\n    coords.into_iter().zip(widths).map(|(pos, pressure)| Element::new(pos + offset, pressure)),\n).ok_or_else(|| anyhow!(\"Could not generate pen path...\"))?;\n// after\nif coords.len() != widths.len() || coords.is_empty() {\n    return Err(anyhow!(\"xopp stroke has {} coords but {} widths\", coords.len(), widths.len()));\n}","handlingStrategy":"validation","validationCode":"if coords.is_empty() || widths.is_empty() || coords.len() != widths.len() {\n    return Err(anyhow!(\"cannot build pen path: {} coords, {} widths\", coords.len(), widths.len()));\n}","typeGuard":"fn buildable_penpath(coords: &[Point], widths: &[f64]) -> bool {\n    !coords.is_empty() && coords.len() == widths.len()\n}","tryCatchPattern":"match Stroke::from_xoppstroke(stroke, offset, dpi) {\n    Ok(res) => res,\n    Err(e) if e.to_string().contains(\"Could not generate pen path\") => {\n        log::warn!(\"empty/unbalanced stroke skipped: {e}\");\n        default_stroke()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Check coords.len() == widths.len() before zipping — zip silently truncates","Reject or repair empty <stroke> elements at parse time","Unit-test the XOPP importer with single-point and zero-width strokes"],"tags":["xopp","import","penpath","empty-input"],"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"}