a-b-street/abstreet · error

This intersection doesn't use fixed timing.

Error message

This intersection doesn't use fixed timing.

What it means

adjust_major_minor_timing only rewrites StageType::Fixed stages. If any stage uses a different StageType (e.g. adaptive/variable timing), the method bails rather than silently overwriting a non-fixed timing policy.

Solutions

  1. Convert all stages to StageType::Fixed before calling adjust_major_minor_timing
  2. Skip signals using non-fixed timing, or use the appropriate API for that timing type
  3. Recreate the signal assignment with default fixed stages
  4. Persist/restore fixed timing before applying major/minor durations

Example fix

// before
signal.adjust_major_minor_timing(major, minor, map)?;
// after
if signal.stages.iter().all(|s| matches!(s.stage_type, StageType::Fixed(_))) {
    signal.adjust_major_minor_timing(major, minor, map)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if !signal.stages.iter().all(|s| matches!(s.stage_type, StageType::Fixed(_))) {
    return Err(anyhow!("signal {} uses non-fixed timing", signal.id));
}

Type guard

fn all_fixed(signal: &TrafficSignal) -> bool {
    signal.stages.iter().all(|s| matches!(s.stage_type, StageType::Fixed(_)))
}

Try / catch

if all_fixed(signal) {
    signal.adjust_major_minor_timing(major, minor, map)?;
} else {
    skip_non_fixed(signal.id);
}

Prevention

When it happens

Trigger: Calling adjust_major_minor_timing on a signal whose stages include a non-Fixed StageType variant, encountered in the loop over self.stages before any duration is modified.

Common situations: Signals loaded from a scenario or edited with adaptive timing; mixing timing plugins/experiments with the fixed major/minor retiming helper.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at map_model/src/objects/traffic_signals.rs:236

        // What's the rank of each road?
        let mut rank_per_road: BTreeMap<RoadID, usize> = BTreeMap::new();
        for r in &map.get_i(self.id).roads {
            rank_per_road.insert(*r, map.get_r(*r).get_detailed_rank());
        }
        let mut ranks: Vec<usize> = rank_per_road.values().cloned().collect();
        ranks.sort_unstable();
        ranks.dedup();
        if ranks.len() == 1 {
            bail!("This intersection doesn't have major/minor roads; they're all the same rank.");
        }
        let highest_rank = ranks.pop().unwrap();

        // Try to apply the transformation
        let orig = self.clone();
        for stage in &mut self.stages {
            match stage.stage_type {
                StageType::Fixed(_) => {}
                _ => bail!("This intersection doesn't use fixed timing."),
            }
            // Ignoring crosswalks, do any of the turns come from a major road?
            if stage
                .protected_movements
                .iter()
                .any(|m| !m.crosswalk && highest_rank == rank_per_road[&m.from.road])
            {
                stage.stage_type = StageType::Fixed(major);
            } else {
                stage.stage_type = StageType::Fixed(minor);
            }
        }

        if self.simple_cycle_duration() != major + minor {
            bail!("This intersection didn't already group major/minor roads together.");
        }

        if self == &orig {

View on GitHub (pinned to 0964f29315)