a-b-street/abstreet · error

Input is missing geo_code

Error message

Input is missing geo_code: {:?}

What it means

parse_zones converts every polygon in a zones GeoJSON into a map zone keyed by the 'geo_code' tag. When any feature's properties lack the geo_code key, it bails, printing the feature's tags so the offending record can be identified.

Solutions

  1. Rename the source property to 'geo_code' in the GeoJSON (e.g. jq '.features[].properties.geo_code = .features[].properties.GSS_CODE').
  2. Regenerate the zones file with a preprocessing script that sets geo_code on every feature.
  3. If you control the code, fall back to alternative tag names (tags.get("geo_code").or_else(|| tags.get("code"))).

Example fix

// before
{"properties": {"GSS_CODE": "E08000025"}}
// after
{"properties": {"geo_code": "E08000025"}}
Defensive patterns

Strategy: validation

Validate before calling

let gj: serde_json::Value = serde_json::from_slice(&bytes)?;
for f in gj["features"].as_array().unwrap() {
    if f["properties"]["geo_code"].is_null() {
        bail!("feature missing geo_code: {:?}", f["properties"]);
    }
}

Type guard

fn has_geo_code(props: &serde_json::Map<String, serde_json::Value>) -> bool {
    props.get("geo_code").map_or(false, |v| v.is_string())
}

Try / catch

match parse_zones(path, gps_bounds, require_in_bounds) {
    Ok(zones) => zones,
    Err(e) if e.to_string().starts_with("Input is missing geo_code") => {
        eprintln!("Rename the zone ID property to geo_code: {e}");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling uk.rs generate_scenario with a zones input file whose features carry a different property name (e.g. 'code', 'GSS_CODE', 'id') instead of 'geo_code', or a feature with empty properties.

Common situations: Using zone shapefiles/GeoJSON from an official source (e.g. ONS boundaries) whose property schema doesn't match the pipeline's expected 'geo_code' key; hand-built GeoJSON missing properties.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at importer/src/uk.rs:201

    #[serde(rename = "Driving a car or van")]
    num_drivers: usize,
    #[serde(rename = "Bicycle")]
    num_bikers: usize,
    #[serde(rename = "On foot")]
    num_pedestrians: usize,
}

// Transforms all zones into the map's coordinate space, no matter how far out-of-bounds they are.
fn parse_zones(gps_bounds: &GPSBounds, path: String) -> Result<HashMap<String, Polygon>> {
    let mut zones = HashMap::new();
    let require_in_bounds = false;
    for (polygon, tags) in
        Polygon::from_geojson_bytes(&abstio::slurp_file(path)?, gps_bounds, require_in_bounds)?
    {
        if let Some(code) = tags.get("geo_code") {
            zones.insert(code.to_string(), polygon);
        } else {
            bail!("Input is missing geo_code: {:?}", tags);
        }
    }
    Ok(zones)
}

fn load_study_area(map: &Map) -> Result<Polygon> {
    let require_in_bounds = true;
    let mut list = Polygon::from_geojson_bytes(
        &abstio::slurp_file(abstio::path(format!(
            "system/study_areas/{}.geojson",
            map.get_name().city.city.replace("_", "-")
        )))?,
        map.get_gps_bounds(),
        require_in_bounds,
    )?;
    if list.len() != 1 {
        bail!("study area geojson has {} polygons", list.len());
    }

View on GitHub (pinned to 0964f29315)