{"record":{"id":"4bd5e7b2c9cb05e7","repo":"a-b-street/abstreet","slug":"input-is-missing-geo-code","errorCode":null,"errorMessage":"Input is missing geo_code: {:?}","messagePattern":"Input is missing geo_code: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"importer/src/uk.rs","lineNumber":201,"sourceCode":"    #[serde(rename = \"Driving a car or van\")]\n    num_drivers: usize,\n    #[serde(rename = \"Bicycle\")]\n    num_bikers: usize,\n    #[serde(rename = \"On foot\")]\n    num_pedestrians: usize,\n}\n\n// Transforms all zones into the map's coordinate space, no matter how far out-of-bounds they are.\nfn parse_zones(gps_bounds: &GPSBounds, path: String) -> Result<HashMap<String, Polygon>> {\n    let mut zones = HashMap::new();\n    let require_in_bounds = false;\n    for (polygon, tags) in\n        Polygon::from_geojson_bytes(&abstio::slurp_file(path)?, gps_bounds, require_in_bounds)?\n    {\n        if let Some(code) = tags.get(\"geo_code\") {\n            zones.insert(code.to_string(), polygon);\n        } else {\n            bail!(\"Input is missing geo_code: {:?}\", tags);\n        }\n    }\n    Ok(zones)\n}\n\nfn load_study_area(map: &Map) -> Result<Polygon> {\n    let require_in_bounds = true;\n    let mut list = Polygon::from_geojson_bytes(\n        &abstio::slurp_file(abstio::path(format!(\n            \"system/study_areas/{}.geojson\",\n            map.get_name().city.city.replace(\"_\", \"-\")\n        )))?,\n        map.get_gps_bounds(),\n        require_in_bounds,\n    )?;\n    if list.len() != 1 {\n        bail!(\"study area geojson has {} polygons\", list.len());\n    }","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/importer/src/uk.rs#L183-L219","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename the source property to 'geo_code' in the GeoJSON (e.g. jq '.features[].properties.geo_code = .features[].properties.GSS_CODE').","Regenerate the zones file with a preprocessing script that sets geo_code on every feature.","If you control the code, fall back to alternative tag names (tags.get(\"geo_code\").or_else(|| tags.get(\"code\")))."],"exampleFix":"// before\n{\"properties\": {\"GSS_CODE\": \"E08000025\"}}\n// after\n{\"properties\": {\"geo_code\": \"E08000025\"}}","handlingStrategy":"validation","validationCode":"let gj: serde_json::Value = serde_json::from_slice(&bytes)?;\nfor f in gj[\"features\"].as_array().unwrap() {\n    if f[\"properties\"][\"geo_code\"].is_null() {\n        bail!(\"feature missing geo_code: {:?}\", f[\"properties\"]);\n    }\n}","typeGuard":"fn has_geo_code(props: &serde_json::Map<String, serde_json::Value>) -> bool {\n    props.get(\"geo_code\").map_or(false, |v| v.is_string())\n}","tryCatchPattern":"match parse_zones(path, gps_bounds, require_in_bounds) {\n    Ok(zones) => zones,\n    Err(e) if e.to_string().starts_with(\"Input is missing geo_code\") => {\n        eprintln!(\"Rename the zone ID property to geo_code: {e}\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Normalize official boundary files with a preprocessing step that sets geo_code","Keep a documented schema for zone inputs and validate on ingest","Check property names with jq '.features[0].properties | keys' before importing"],"tags":["geojson","missing-property","importer","uk"],"backgroundTag":"missing-required-argument","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}