a-b-street/abstreet · error

Negative dist_ahead?!

Error message

Negative dist_ahead?! {}

What it means

Path::exact_slice slices a path to a requested distance ahead; a negative dist_ahead is meaningless, so the method panics with "Negative dist_ahead?!". Zero distance is handled separately as a normal Err. This is a caller contract check: distances passed for slicing must be non-negative.

Solutions

  1. Clamp the distance before calling: Some(d.max(Distance::ZERO))
  2. Skip the slice call when the computed remaining distance is <= zero
  3. Fix the upstream arithmetic that produced the negative distance (usually a subtraction without a floor)
  4. Pass None when you do not need a bounded slice

Example fix

// before
let slice = path.exact_slice(map, start, Some(remaining))?,;
// after
let d = remaining.max(Distance::ZERO);
let slice = if d == Distance::ZERO { None } else { Some(path.exact_slice(map, start, Some(d))?) };
Defensive patterns

Strategy: validation

Validate before calling

fn safe_dist_ahead(d: Distance) -> Option<Distance> {
    if d < Distance::ZERO { None } else { Some(d) }
}

Type guard

fn non_negative(d: Distance) -> Option<Distance> {
    if d >= Distance::ZERO { Some(d) } else { None }
}

Try / catch

// method returns Result and only panics on negatives; clamp first:
match path.exact_slice(map, start, Some(d.max(Distance::ZERO))) {
    Ok(slice) => handle(slice),
    Err(e) => handle_zero_slice(e), // catches "0 dist ahead" via bail!
}

Prevention

When it happens

Trigger: Calling exact_slice with dist_ahead = Some(negative Distance), typically from an arithmetic result that underflowed (e.g. remaining_distance - dist_already_traveled going below zero).

Common situations: Slice/trim logic that computes the lookahead distance by subtraction and can go negative at path endpoints; sim agents requesting a slice past the end of a route with signed math.

Related errors


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

Appendix: source

Thrown at map_model/src/pathfind/v1.rs:53

    pub fn as_lane(&self) -> LaneID {
        self.as_traversable().as_lane()
    }

    pub fn as_turn(&self) -> TurnID {
        self.as_traversable().as_turn()
    }

    // start is relative to the start of the actual geometry -- so from the lane's real start for
    // ContraflowLane.
    fn exact_slice(
        &self,
        map: &Map,
        start: Distance,
        dist_ahead: Option<Distance>,
    ) -> Result<PolyLine> {
        if let Some(d) = dist_ahead {
            if d < Distance::ZERO {
                panic!("Negative dist_ahead?! {}", d);
            }
            if d == Distance::ZERO {
                bail!("0 dist ahead for slice");
            }
        }

        match self {
            PathStep::Lane(id) => {
                let pts = &map.get_l(*id).lane_center_pts;
                if let Some(d) = dist_ahead {
                    pts.maybe_exact_slice(start, start + d)
                } else {
                    pts.maybe_exact_slice(start, pts.length())
                }
            }
            PathStep::ContraflowLane(id) => {
                let pts = map.get_l(*id).lane_center_pts.reversed();
                let reversed_start = pts.length() - start;

View on GitHub (pinned to 0964f29315)