{"record":{"id":"7916fe0c851b3e04","repo":"a-b-street/abstreet","slug":"cityname-new-has-a-country-code-that-isn-t-two-letters","errorCode":null,"errorMessage":"CityName::new({}, {}) has a country code that isn't two letters","messagePattern":"CityName::new\\((.+?), (.+?)\\) has a country code that isn't two letters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"abstio/src/abst_paths.rs","lineNumber":83,"sourceCode":"        format!(\"{dir}/{p}\")\n    }\n}\n\n/// A single city is identified using this.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\npub struct CityName {\n    /// A two letter lowercase country code, from https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2.\n    /// To represent imaginary/test cities, use the code `zz`.\n    pub country: String,\n    /// The name of the city, in filename-friendly form -- for example, \"tel_aviv\".\n    pub city: String,\n}\n\nimpl CityName {\n    /// Create a CityName from a country code and city.\n    pub fn new(country: &str, city: &str) -> CityName {\n        if country.len() != 2 {\n            panic!(\n                \"CityName::new({}, {}) has a country code that isn't two letters\",\n                country, city\n            );\n        }\n        CityName {\n            country: country.to_string(),\n            city: city.to_string(),\n        }\n    }\n\n    /// Convenient constructor for the main city of the game.\n    pub fn seattle() -> CityName {\n        CityName::new(\"us\", \"seattle\")\n    }\n\n    /// Returns all city names available locally.\n    fn list_all_cities_locally() -> Vec<CityName> {\n        let mut cities = Vec::new();","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/abst_paths.rs#L65-L101","documentation":"CityName::new validates that the country argument is exactly two characters (an ISO 3166-1 alpha-2 code, lowercase, or 'zz' for imaginary cities) because the country code is used as a directory name in path construction. Passing a longer (or shorter) string panics with this message.","triggerScenarios":"Calling CityName::new(country, city), MapName::new(country, city, map), or CityName::parse with a country string whose byte length is not 2 — e.g. 'usa', 'US' is fine length-wise but 'USA', 'United States', or an empty string will panic. list_all_cities_locally / list_all_cities_from_importer_config also hit this if a directory under data/system/ or importer/config/ is not a two-letter code.","commonSituations":"Hardcoding 'usa' instead of 'us', using full country names, creating a stray misnamed directory (e.g. data/system/misc/) that gets scanned as a country, or user-supplied input passed straight into CityName::new.","solutions":["Pass a valid two-letter ISO 3166-1 alpha-2 lowercase code (e.g. 'us', 'gb', 'zz' for test cities)","Use CityName::parse('us/seattle') or the built-in constructors like CityName::seattle() / MapName::seattle(map) instead of hand-building names","Rename any non-two-letter directories under data/system/ or importer/config/ so directory scans don't produce invalid codes","Validate the country string before calling: check country.len() == 2 and use CityName::parse or your own Result-returning wrapper for external input"],"exampleFix":"// before\nlet city = CityName::new(\"usa\", \"seattle\"); // panics\n// after\nlet city = CityName::new(\"us\", \"seattle\");\n// or validated:\nassert_eq!(country.len(), 2);\nlet city = CityName::parse(&format!(\"{}/{}\", country, city_name))?;","handlingStrategy":"validation","validationCode":"fn valid_country_code(country: &str) -> bool {\n    country.len() == 2 && country.chars().all(|c| c.is_ascii_lowercase())\n}\n// call only if valid_country_code(country) else handle/reprompt","typeGuard":"fn as_country_code(s: &str) -> Option<&str> {\n    (s.len() == 2 && s.chars().all(|c| c.is_ascii_lowercase())).then_some(s)\n}","tryCatchPattern":"let city = std::panic::catch_unwind(|| CityName::new(country, city))\n    .map_err(|_| anyhow::anyhow!(\"country code '{}' must be two letters\", country))?;","preventionTips":["Always use ISO 3166-1 alpha-2 lowercase codes ('us', 'gb', 'zz' for imaginary cities)","Prefer CityName::parse or built-in constructors (CityName::seattle, MapName::seattle) over manual construction","Keep directories under data/system/ and importer/config/ named with two-letter codes only","Validate external/user-supplied country strings before passing to CityName::new or MapName::new"],"tags":["rust","panic","validation","country-code","identifier"],"backgroundTag":"invalid-argument-format","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"}