{"record":{"id":"a0e9dde50f4aa8e2","repo":"a-b-street/abstreet","slug":"traffic-signal-does-not-allow-enough-time-in-stage-to","errorCode":null,"errorMessage":"Traffic signal does not allow enough time in stage to complete the crosswalk\nStage Index{}\nStage : {:?}\nTime Required: {}\nTime Given: {}","messagePattern":"Traffic signal does not allow enough time in stage to complete the crosswalk\nStage Index(.+?)\nStage : (.+?)\nTime Required: (.+?)\nTime Given: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/objects/traffic_signals.rs","lineNumber":130,"sourceCode":"                        bail!(\n                            \"Traffic signal has conflicting protected movements in one \\\n                             stage:\\n{:?}\\n\\n{:?}\",\n                            m1,\n                            m2\n                        );\n                    }\n                }\n            }\n\n            // Do any of the crosswalks yield?\n            for m in stage.yield_movements.iter().map(|m| &i.movements[m]) {\n                // TODO Maybe make UnmarkedCrossing yield\n                assert!(!m.turn_type.pedestrian_crossing())\n            }\n            // Is there enough time in each stage to walk across the crosswalk\n            let min_crossing_time = self.get_min_crossing_time(stage_index, i);\n            if stage.stage_type.simple_duration() < min_crossing_time {\n                bail!(\n                    \"Traffic signal does not allow enough time in stage to complete the \\\n                     crosswalk\\nStage Index{}\\nStage : {:?}\\nTime Required: {}\\nTime Given: {}\",\n                    stage_index,\n                    stage,\n                    min_crossing_time,\n                    stage.stage_type.simple_duration()\n                );\n            }\n        }\n        Ok(())\n    }\n\n    /// Move crosswalks from stages, adding them to an all-walk as last stage. This may promote\n    /// yields to protected. True is returned if any stages were added or modified.\n    pub fn convert_to_ped_scramble(&mut self, i: &Intersection) -> bool {\n        self.internal_convert_to_ped_scramble(true, i)\n    }\n    /// Move crosswalks from stages, adding them to an all-walk as last stage. This does not promote","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/objects/traffic_signals.rs#L112-L148","documentation":"TrafficSignal::validate ensures each stage's duration is at least the minimum time a pedestrian needs to finish crossing any crosswalk in that stage. If the stage's simple_duration is shorter than get_min_crossing_time for the stage, the signal would strand pedestrians mid-crossing, so import bails.","triggerScenarios":"Setting a StageType::Fixed duration below the computed pedestrian crossing time for the stage's crosswalks (long/wide crossings, or very short stage times); affecting pedestrian and unprotected turn movements in the stage.","commonSituations":"Aggressively shortening cycle times to reduce car delay; importing maps where crosswalks span very wide roads; tuning signal timings by hand without checking walk times.","solutions":["Increase the stage's Fixed duration to at least get_min_crossing_time for that stage index","Shorten or reroute the crosswalk, or move the crosswalk's protected time to a longer stage","Use adjust_major_minor_timing or another helper that respects minimum crossing times instead of raw duration edits","Compute and print min crossing times per stage before tuning durations"],"exampleFix":"// before\nstage.stage_type = StageType::Fixed(Duration::seconds(5));\n// after\nlet min_time = signal.get_min_crossing_time(stage_idx, intersection);\nstage.stage_type = StageType::Fixed(min_time.max(Duration::seconds(5)));","handlingStrategy":"validation","validationCode":"let need = signal.get_min_crossing_time(idx, i);\nif stage.stage_type.simple_duration() < need {\n    stage.stage_type = StageType::Fixed(need);\n}","typeGuard":"fn duration_safe(stage: &Stage, idx: usize, i: &Intersection) -> bool {\n    stage.stage_type.simple_duration() >= /* need access via signal */ true\n}","tryCatchPattern":"match signal.adjust_stage_duration(idx, new_time, i) {\n    Err(e) => eprintln!(\"raise duration or shorten crosswalk: {e}\"),\n    Ok(_) => {}\n}","preventionTips":["Clamp every stage duration to at least the stage's min crossing time before assigning","Compute crossing times for wide crossings before shortening cycle times","Never hand-set Fixed durations below computed pedestrian requirements"],"tags":["traffic-signals","pedestrian","validation"],"backgroundTag":"value-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"}