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

  1. Recreate the edits from scratch in the current version and save a new file, as the message says.
  2. Check if an intermediate binary release that still wrote v12-compat upgrades is available to migrate the file first.
  3. 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

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


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)