a-b-street/abstreet · error
Breaking changes happened to map edits between v12 and v13…
Error message
Breaking changes happened to map edits between v12 and v13. Recreate your edits from scratch; sorry.
What it means
The edits compat layer upgrades older serialized map-edits JSON version by version. Version 12 files cannot be mechanically upgraded to 13 because the schema changed incompatibly, so upgrade() deliberately bails telling the user to recreate their edits rather than producing silently wrong output.
Solutions
- Recreate the edits from scratch in the current version and save a new file, as the message says.
- Check if an intermediate binary release that still wrote v12-compat upgrades is available to migrate the file first.
- If the edits are simple, hand-edit the JSON to the current schema and bump 'version', validating against the current struct definitions.
Defensive patterns
Strategy: fallback
Validate before calling
let v: serde_json::Value = serde_json::from_slice(&bytes)?;
if v["version"].as_i64() == Some(12) {
bail!("edits file is v12 and cannot be auto-upgraded; recreate or migrate it first");
} Try / catch
match Edits::load(path) {
Ok(e) => e,
Err(e) if e.to_string().contains("between v12 and v13") => {
eprintln!("Old edits file can't be migrated ({e}); recreating edits from scratch.");
Edits::default()
}
Err(e) => return Err(e),
} Prevention
- Keep saving edits with the current tool version
- Back up edits files and note their version before upgrading the tool
- Read release notes for breaking schema changes before loading old saves
When it happens
Trigger: Loading a saved map edits JSON file whose 'version' field is 12 through the current code (which only knows upgrades into v12 and later, and refuses 12->13).
Common situations: Opening an old saved edits/preset file (e.g. from an older abstreet release or a shared backup) with a newer binary; resuming an old experiment after upgrading the tool.
Understand the failure class
Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.
Related errors
- must_get_sidewalk broken by
- doesn't contain both and
- lane type has changed
- 's road doesn't point to dst_i at all
- 's road already points to dst_i
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/d0db9f5c38537875.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/edits/compat.rs:121
.unwrap()
.insert("version".to_string(), Value::Number(10.into()));
}
if value["version"] == Value::Number(10.into()) {
remove_vehicle_caps(&mut value);
value
.as_object_mut()
.unwrap()
.insert("version".to_string(), Value::Number(11.into()));
}
if value["version"] == Value::Number(11.into()) {
fix_turn_restrictions(&mut value);
value
.as_object_mut()
.unwrap()
.insert("version".to_string(), Value::Number(12.into()));
}
if value["version"] == Value::Number(12.into()) {
bail!("Breaking changes happened to map edits between v12 and v13. Recreate your edits from scratch; sorry.");
}
abstutil::from_json(&value.to_string().into_bytes())
}
// Recursively walks the entire JSON object. Will call transform on all of the map objects. If the
// callback returns true, won't recurse into that map.
fn walk<F: Fn(&mut serde_json::Map<String, Value>) -> bool>(value: &mut Value, transform: &F) {
match value {
Value::Array(list) => {
for x in list {
walk(x, transform);
}
}
Value::Object(map) => {
if !(transform)(map) {
for x in map.values_mut() {
walk(x, transform);View on GitHub (pinned to 0964f29315)