a-b-street/abstreet · error · anyhow::Error

Person ( ) starts two trips in the wrong order: then

Error message

Person ({:?}) starts two trips in the wrong order: {} then {}

What it means

check_schedule requires trips to be sorted by departure time. If any adjacent pair has pair[0].depart >= pair[1].depart, the schedule is invalid and this error names the person and both departure times.

Solutions

  1. Sort the trips by departure time before calling check_schedule
  2. Break ties by nudging one departure slightly later or merging trips
  3. Validate/sort in the import pipeline before constructing the scenario

Example fix

// before
let spec = PersonSpec { trips: trips, .. };
// after
trips.sort_by_key(|t| t.depart);
let spec = PersonSpec { trips, .. };
Defensive patterns

Strategy: validation

Validate before calling

person.trips.sort_by_key(|t| t.depart);

Try / catch

match person.check_schedule() {
    Ok(()) => {},
    Err(e) if e.to_string().contains("wrong order") => {
        person.trips.sort_by_key(|t| t.depart);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Building a PersonSpec whose trips are not strictly increasing in departure time, including trips that depart at exactly the same time.

Common situations: External population files with unsorted trips, merging multiple data sources without re-sorting, floating/second-granularity collisions producing equal timestamps.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at synthpop/src/scenario.rs:173

                    return x.to_string();
                }
            }
        }
        // Dynamically generated -- arguably this is an absence of a default scenario
        "home_to_work".to_string()
    }
}

impl PersonSpec {
    /// Verify that a person's trips make sense
    pub fn check_schedule(&self) -> Result<()> {
        if self.trips.is_empty() {
            bail!("Person ({:?}) has no trips at all", self.orig_id);
        }

        for pair in self.trips.windows(2) {
            if pair[0].depart >= pair[1].depart {
                bail!(
                    "Person ({:?}) starts two trips in the wrong order: {} then {}",
                    self.orig_id,
                    pair[0].depart,
                    pair[1].depart
                );
            }

            if pair[0].destination != pair[1].origin {
                // Exiting one border and re-entering another is fine
                if matches!(pair[0].destination, TripEndpoint::Border(_))
                    && matches!(pair[1].origin, TripEndpoint::Border(_))
                {
                    continue;
                }
                bail!(
                    "Person ({:?}) warps from {:?} to {:?} during adjacent trips",
                    self.orig_id,
                    pair[0].destination,

View on GitHub (pinned to 0964f29315)