a-b-street/abstreet · error

Transit route will warp from

Error message

Transit route will warp from {} to {}

What it means

After collecting per-leg paths, all_paths verifies that consecutive paths are contiguous: the end of path[i] must equal the start of path[i+1]. A mismatch means the transit vehicle would teleport ("warp") between positions, so the route is rejected. This catches routes whose stop sequence is not a connected chain of drivable paths.

Solutions

  1. Check the two positions in the message; ensure the intermediate stop connects both legs — often the middle stop is unreachable so its leg silently deviates.
  2. Reorder or insert stops so the sequence forms a continuous forward chain.
  3. Recompute routes after any map geometry/connectivity changes.
  4. Fix unreachable map segments (missing connections) that make one leg's path terminate elsewhere.

Example fix

// before: route [A, C, B] where C is off the A->B corridor
let stops = vec![a, c, b];
// after: order stops along the actual travel corridor
let stops = vec![a, b, c];
Defensive patterns

Strategy: validation

Validate before calling

for pair in stops.windows(2) {
    let req = PathRequest::vehicle(pair[0], pair[1], mode);
    let path = map.pathfind(req)?;
    if path.end() != next_leg_start(pair[1]) {
        return Err("discontinuous stop chain".into());
    }
}

Try / catch

match route.all_paths(&map) {
    Err(e) if e.to_string().starts_with("Transit route will warp") => {
        // recompute/reorder stops based on the two positions in the message
    }
    other => other?,
}

Prevention

When it happens

Trigger: create_route / create_empty_route where for some adjacent pair, pair[0].get_req().end != pair[1].get_req().start (map_model/src/objects/transit.rs:130) — e.g. the path from stop A ends at a location different from where the path to stop C begins.

Common situations: Stop lists edited out of order, stops on disconnected parts of the map after edits, or route definitions reused across different map versions whose paths changed.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/77e218f05944c404. Report an issue: GitHub.

Appendix: source

Thrown at map_model/src/objects/transit.rs:130

            if req.start.lane().road == req.end.lane().road
                && req.start.dist_along() > req.end.dist_along()
            {
                bail!(
                    "Two consecutive stops are on the same road, but they travel backwards: {}",
                    req
                );
            }

            let path = map.pathfind(req)?;
            if path.is_empty() {
                bail!("Empty path between stops: {}", path.get_req());
            }
            paths.push(path);
        }

        for pair in paths.windows(2) {
            if pair[0].get_req().end != pair[1].get_req().start {
                bail!(
                    "Transit route will warp from {} to {}",
                    pair[0].get_req().end,
                    pair[1].get_req().start
                );
            }
        }

        Ok(paths)
    }

    pub fn plural_noun(&self) -> &'static str {
        if self.route_type == PathConstraints::Bus {
            "buses"
        } else {
            "trains"
        }
    }
}

View on GitHub (pinned to 0964f29315)