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

  1. Filter out non-XML control characters from the text before calling render_curvey.
  2. Reproduce with the exact text from the panic message and minimize it.
  3. 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

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)