{"record":{"id":"b7900b749e9da7eb","repo":"a-b-street/abstreet","slug":"can-t-spawn-at-it-isn-t-that-long","errorCode":null,"errorMessage":"Can't spawn at {}; it isn't that long","messagePattern":"Can't spawn at (.+?); it isn't that long","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sim/src/make/spawner.rs","lineNumber":72,"sourceCode":"        route: TransitRouteID,\n        stop1: TransitStopID,\n        maybe_stop2: Option<TransitStopID>,\n    },\n}\n\nimpl TripSpec {\n    pub fn into_plan(self, map: &Map) -> (TripSpec, Vec<TripLeg>) {\n        // TODO We'll want to repeat this validation when we spawn stuff later for a second leg...\n        let mut legs = Vec::new();\n        match &self {\n            TripSpec::VehicleAppearing {\n                start_pos,\n                goal,\n                use_vehicle,\n                ..\n            } => {\n                if start_pos.dist_along() >= map.get_l(start_pos.lane()).length() {\n                    panic!(\"Can't spawn at {}; it isn't that long\", start_pos);\n                }\n                if let DrivingGoal::Border(_, end_lane) = goal {\n                    if start_pos.lane() == *end_lane\n                        && start_pos.dist_along() == map.get_l(*end_lane).length()\n                    {\n                        panic!(\n                            \"Can't start at {}; it's the edge of a border already\",\n                            start_pos\n                        );\n                    }\n                }\n\n                let constraints = if use_vehicle.vehicle_type == VehicleType::Bike {\n                    PathConstraints::Bike\n                } else {\n                    PathConstraints::Car\n                };\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/sim/src/make/spawner.rs#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Clamp dist_along to be strictly less than the lane length before spawning","Pick a different lane or shift the spawn back from the lane end","Regenerate the scenario against the current (possibly edited) map geometry"],"exampleFix":"// before\nlet pos = Position::new(lane, length);\n// after\nlet pos = Position::new(lane, length - Distance::meters(0.1)).min_lane_end();","handlingStrategy":"validation","validationCode":"let lane_len = map.get_l(start_pos.lane()).length();\nif start_pos.dist_along() >= lane_len {\n    start_pos = start_pos.min_lane_end(); // clamp before building TripSpec\n}","typeGuard":"fn spawnable(pos: &Position, map: &Map) -> bool {\n    pos.dist_along() < map.get_l(pos.lane()).length()\n}","tryCatchPattern":"let plan = std::panic::catch_unwind(|| spec.into_plan(&map, &mut rng));","preventionTips":["Clamp dist_along to length - epsilon when sampling uniformly along lanes","Regenerate scenarios after map edits change lane lengths"],"tags":["rust","panic","value-out-of-range","simulation"],"backgroundTag":"argument-out-of-range","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}