a-b-street/abstreet · error

Malformed coordinates

Error message

Malformed coordinates: {}

What it means

While recursing through KML, each <coordinates> element is parsed as space/comma-separated lon,lat pairs. When any pair fails to parse (wrong number of components or non-numeric text), recurse bails with the offending pair included in the message.

Solutions

  1. Open the KML, find the pair printed in the error, and fix or remove it — coordinates must be numeric lon,lat (optionally alt) triples like '-1.2,54.5,0'.
  2. Normalize the file: replace locale decimal commas with dots and strip empty tokens before loading.
  3. If the file comes from an external tool, re-export it with plain 2D WGS84 coordinates.

Example fix

// before (KML coordinates)
-1.2,54.5,0 -1,3,54,6
// after
-1.2,54.5,0 -1.3,54.6,0
Defensive patterns

Strategy: validation

Validate before calling

for pair in coords_text.split_whitespace() {
    let parts: Vec<&str> = pair.split(',').collect();
    if !(2..=3).contains(&parts.len()) || parts.iter().any(|p| p.parse::<f64>().is_err()) {
        bail!("Malformed coordinates: {}", pair);
    }
}

Type guard

fn is_valid_coord_pair(pair: &str) -> bool {
    pair.split(',').map(str::trim).filter(|p| !p.is_empty())
        .take(2).count() >= 2
        && pair.split(',').take(2).all(|p| p.trim().parse::<f64>().is_ok())
}

Try / catch

match load_kml(path, ...) {
    Ok(shapes) => shapes,
    Err(e) if e.to_string().starts_with("Malformed coordinates") => {
        eprintln!("Fix the KML coordinate pair: {e}");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Loading a KML file whose Placemark coordinates contain malformed entries — e.g. 'lat,lon,alt,extra', 'x,y' with non-numeric values, doubled commas, or newline-only junk between valid pairs.

Common situations: Hand-edited KML; KML exported by tools that emit 3D coordinates or locale-formatted decimals (comma decimal separators); copy-pasted coordinate strings with stray characters.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/10ff571aeaabd392. Report an issue: GitHub.

Appendix: source

Thrown at kml/src/lib.rs:113

            .text()
            .map(|x| x.to_string())
            .unwrap_or_else(String::new);
        kv.insert(key, value);
    } else if node.tag_name().name() == "coordinates" {
        let mut any_oob = false;
        let mut any_ok = false;
        let mut pts: Vec<LonLat> = Vec::new();
        if let Some(txt) = node.text() {
            for pair in txt.trim().split(' ') {
                if let Some(pt) = parse_pt(pair) {
                    pts.push(pt);
                    if gps_bounds.contains(pt) {
                        any_ok = true;
                    } else {
                        any_oob = true;
                    }
                } else {
                    bail!("Malformed coordinates: {}", pair);
                }
            }
        }
        if any_ok && (!any_oob || !require_all_pts_in_bounds) {
            let attributes = std::mem::take(kv);
            shapes.push(ExtraShape {
                points: pts,
                attributes,
            });
        } else {
            *skipped_count += 1;
        }
    }
    Ok(())
}

fn parse_pt(input: &str) -> Option<LonLat> {
    let coords: Vec<&str> = input.split(',').collect();

View on GitHub (pinned to 0964f29315)