a-b-street/abstreet · error

Can't spawn at ; it isn't that long

Error message

Can't spawn at {}; it isn't that long

What it means

When turning spawn specifications into trip plans, a TripSpec starting at a Position whose dist_along exceeds or equals the lane's total length cannot be placed on that lane. The library panics because there is no valid geometry for a car beyond the end of its lane.

Solutions

  1. Clamp dist_along to be strictly less than the lane length before spawning
  2. Pick a different lane or shift the spawn back from the lane end
  3. Regenerate the scenario against the current (possibly edited) map geometry

Example fix

// before
let pos = Position::new(lane, length);
// after
let pos = Position::new(lane, length - Distance::meters(0.1)).min_lane_end();
Defensive patterns

Strategy: validation

Validate before calling

let lane_len = map.get_l(start_pos.lane()).length();
if start_pos.dist_along() >= lane_len {
    start_pos = start_pos.min_lane_end(); // clamp before building TripSpec
}

Type guard

fn spawnable(pos: &Position, map: &Map) -> bool {
    pos.dist_along() < map.get_l(pos.lane()).length()
}

Try / catch

let plan = std::panic::catch_unwind(|| spec.into_plan(&map, &mut rng));

Prevention

When it happens

Trigger: into_plan() called with a TripSpec::Vehicle whose start_pos.dist_along() >= map.get_l(start_pos.lane()).length(), e.g. a spawn position at or past the lane end.

Common situations: Scenario generators computing dist_along from percentages without clamping (1.0 * length); floating-point rounding pushing dist_along just past the lane length; reusing positions from a differently-edited map where lanes were shortened by edits.

Related errors


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

Appendix: source

Thrown at sim/src/make/spawner.rs:72

        route: TransitRouteID,
        stop1: TransitStopID,
        maybe_stop2: Option<TransitStopID>,
    },
}

impl TripSpec {
    pub fn into_plan(self, map: &Map) -> (TripSpec, Vec<TripLeg>) {
        // TODO We'll want to repeat this validation when we spawn stuff later for a second leg...
        let mut legs = Vec::new();
        match &self {
            TripSpec::VehicleAppearing {
                start_pos,
                goal,
                use_vehicle,
                ..
            } => {
                if start_pos.dist_along() >= map.get_l(start_pos.lane()).length() {
                    panic!("Can't spawn at {}; it isn't that long", start_pos);
                }
                if let DrivingGoal::Border(_, end_lane) = goal {
                    if start_pos.lane() == *end_lane
                        && start_pos.dist_along() == map.get_l(*end_lane).length()
                    {
                        panic!(
                            "Can't start at {}; it's the edge of a border already",
                            start_pos
                        );
                    }
                }

                let constraints = if use_vehicle.vehicle_type == VehicleType::Bike {
                    PathConstraints::Bike
                } else {
                    PathConstraints::Car
                };

View on GitHub (pinned to 0964f29315)