a-b-street/abstreet · error
curvey( )
Error message
curvey({}): {} What it means
render_curvey generates an SVG with text placed along a curve and parses it with usvg; Tree::from_str failure panics with the text and parser error. As with render_line, the generated markup or its content failed XML/SVG parsing.
Solutions
- Filter out non-XML control characters from the text before calling render_curvey.
- Reproduce with the exact text from the panic message and minimize it.
- Fall back to render_line for texts that fail curvey parsing.
Example fix
// before Text::curvey(text, curve); // after let safe: String = text.chars().filter(|c| !c.is_control()).collect(); Text::curvey(safe, curve);
Defensive patterns
Strategy: validation
Validate before calling
let safe: String = text.chars().filter(|c| !c.is_control()).collect(); assert!(htmlescape::encode_minimal(&safe).chars().all(|c| c as u32 >= 0x20 || c == '\n'));
Try / catch
// Fall back to straight-line text if curvey parsing fails:
match renderable_curvey(&safe, curve) { Some(t) => t, None => Text::from(safe) } Prevention
- Sanitize curved-label text (control chars, invalid XML chars)
- Test curvey labels with real map/user data strings
- Keep a fallback plain-text renderer for problematic labels
When it happens
Trigger: Calling render_curvey with self.text that produces invalid SVG after htmlescape encoding — e.g. strings with invalid XML control characters, or an upstream regression in the generated <path>/<text> markup.
Common situations: Curved labels built from user input or map data containing odd bytes; text containing characters that survive htmlescape but are still invalid XML (e.g. most control chars, lone surrogates).
Related errors
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/4476ae7ed2ad20a5.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/text.rs:619
_ => "",
},
fg_color.as_hex(),
fg_color.a,
start_offset,
stroke_parameters,
)
.unwrap();
write!(
&mut svg,
r##"<textPath href="#txtpath">{}</textPath></text></svg>"##,
htmlescape::encode_minimal(&self.text)
)
.unwrap();
let mut svg_tree = match usvg::Tree::from_str(&svg, &usvg::Options::default()) {
Ok(t) => t,
Err(err) => panic!("curvey({}): {}", self.text, err),
};
svg_tree.convert_text(&assets.fontdb.borrow());
let mut batch = GeomBatch::new();
match crate::svg::add_svg_inner(&mut batch, svg_tree, tolerance) {
Ok(_) => batch,
Err(err) => {
error!("render_curvey({}): {}", self.text, err);
batch
}
}
}
}
View on GitHub (pinned to 0964f29315)