a-b-street/abstreet · error
Unknown dpurp
Error message
Unknown dpurp {} What it means
get_purpose maps the Soundcast trip file's dpurp column (a string code like "1.0".."10.0") to a TripPurpose enum. Any dpurp value outside the enumerated set panics with "Unknown dpurp {code}". The import is intentionally strict: an unmodeled purpose would silently corrupt scenario data.
Solutions
- Inspect the offending row's dpurp value in the trip file and correct or impute a known code.
- Add a mapping arm for the new code (or a default like TripPurpose::Home / Err) in get_purpose if the model version legitimately introduced it.
- Pre-filter/normalize the TSV (map blank/NA to "0.0" = not home-to-home per the wiki) before import.
- Pin to the Soundcast model version the importer was written against (see psrc/soundcast wiki Outputs docs).
Example fix
// before
_ => panic!("Unknown dpurp {}", code),
// after
other => {
warn!("Unknown dpurp {}, defaulting to Home", other);
TripPurpose::Home
} Defensive patterns
Strategy: validation
Validate before calling
const KNOWN_DPURP: [&str; 11] = ["0.0","1.0","2.0","3.0","4.0","5.0","6.0","7.0","8.0","9.0","10.0"];
let bad: Vec<_> = rows.iter().filter(|r| !KNOWN_DPURP.contains(&r.dpurp.as_str())).collect();
assert!(bad.is_empty(), "unknown dpurp values: {:?}", bad); Type guard
fn is_known_dpurp(code: &str) -> bool {
matches!(code, "0.0"|"1.0"|"2.0"|"3.0"|"4.0"|"5.0"|"6.0"|"7.0"|"8.0"|"9.0"|"10.0")
} Try / catch
// Panics uncatchably; sanitize before import:
let dpurp = if is_known_dpurp(raw) { raw } else { "0.0".to_string() }; Prevention
- Pre-validate _trip.tsv columns against the wiki's enumerated codes.
- Normalize blanks/NA to "0.0" before importing.
- Pin input data to the Soundcast model version the importer supports.
When it happens
Trigger: Calling import_trips on a _trip.tsv whose dpurp column contains a value not in 0.0-10.0 (e.g. empty string, "11.0", "NA", non-numeric junk).
Common situations: A newer Soundcast model version changing the purpose codes; corrupted or hand-edited trip files; regional model variants (different PSRC output years) using extra categories; blank cells in the TSV.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Unknown mode
- Some IndividTrip wasn't associated with a Person?!
- This build of A/B Street stores player data in…
- Can't find the data/ directory
- CityName::new( , ) has a country code that isn't two letters
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/d2e887b8df7cb5ea.
Report an issue: GitHub.
Appendix: source
Thrown at importer/src/soundcast/popdat.rs:250
) -> (HashMap<usize, Endpoint>, BTreeMap<usize, ExtraShape>) {
panic!("Can't import_parcels for popdat.bin without the scenarios feature (GDAL dependency)");
}
// From https://github.com/psrc/soundcast/wiki/Outputs#trip-file-_triptsv, dpurp
fn get_purpose(code: &str) -> TripPurpose {
match code {
"0.0" => TripPurpose::Home,
"1.0" => TripPurpose::Work,
"2.0" => TripPurpose::School,
"3.0" => TripPurpose::Escort,
"4.0" => TripPurpose::PersonalBusiness,
"5.0" => TripPurpose::Shopping,
"6.0" => TripPurpose::Meal,
"7.0" => TripPurpose::Social,
"8.0" => TripPurpose::Recreation,
"9.0" => TripPurpose::Medical,
"10.0" => TripPurpose::ParkAndRideTransfer,
_ => panic!("Unknown dpurp {}", code),
}
}
// From https://github.com/psrc/soundcast/wiki/Outputs#trip-file-_triptsv, mode
fn get_mode(code: &str) -> TripMode {
match code {
"1.0" => TripMode::Walk,
"2.0" => TripMode::Bike,
"3.0" | "4.0" | "5.0" => TripMode::Drive,
// TODO Park-and-ride and school bus as walk-to-transit is a little weird.
"6.0" | "7.0" | "8.0" => TripMode::Transit,
// TODO Invalid code, what's this one mean? I only see a few examples, so just default to
// walking.
"0.0" => TripMode::Walk,
_ => panic!("Unknown mode {}", code),
}
}
View on GitHub (pinned to 0964f29315)