All rules below validate against TODS v2.1.0. Severities:
- ERROR: the feed violates the spec; consumers may misread or drop data.
- WARNING: probably a mistake, but the spec does not forbid it.
- INFO: worth knowing; no action required.
Rules that resolve IDs into the companion GTFS feed run only when one is
available (via --gtfs or GTFS files alongside the TODS files).
Severity: WARNING.
The package contains none of the ten files defined by TODS. Every TODS file is optional, but a package with none of them has nothing to validate.
Spec reference: https://tods-transit.org/spec/#files
Severity: INFO.
A file in the package is neither a TODS file nor a standard GTFS file. It is ignored by this validator.
Spec reference: https://tods-transit.org/spec/#files
Severity: ERROR.
A TODS file is empty, not UTF-8 encoded, or not parseable as CSV. The file's contents were not validated.
Spec reference: https://tods-transit.org/spec/#files
Severity: ERROR.
A row has more or fewer values than the file's header declares columns. Values after the mismatch may be attributed to the wrong field.
Example: Before: header is trip_id,stop_sequence,arrival_time but a data row is T-1,1,08:00,extra. After: quote fields containing commas, or remove the stray trailing value so the row has exactly 3 fields.
Spec reference: https://tods-transit.org/spec/#files
Severity: ERROR.
A column name appears more than once in a file's header row.
Spec reference: https://tods-transit.org/spec/#files
Severity: ERROR.
A TODS file does not declare a column the spec marks Required (for supplement files: a primary-key column of the GTFS file being supplemented). Rows cannot be interpreted without it.
Example: Before: stop_time_overrides.txt header is trip_id,stop_sequence. After: add the required key column — trip_id,stop_id,stop_sequence.
Spec reference: https://tods-transit.org/spec/
Severity: WARNING.
A TODS-specific file declares a column the spec does not define. Consumers will ignore it; it is often a misspelled field name.
Spec reference: https://tods-transit.org/spec/
Severity: INFO.
A supplement file declares a column that is neither a field of the GTFS file being supplemented nor a TODS_ field. It is carried through to the merged feed as a GTFS extension field.
Spec reference: https://tods-transit.org/spec/#supplement-files
Severity: ERROR.
A field the spec marks Required is empty (for supplement files: a primary-key field, without which the row cannot be matched to GTFS).
Spec reference: https://tods-transit.org/spec/
Severity: ERROR.
An enum field has a value outside the options the spec allows (TODS_delete: blank or 1; start_mid_trip and end_mid_trip: blank, 0, 1, or 2).
Spec reference: https://tods-transit.org/spec/
Severity: ERROR.
A value does not match its field type: times must be HH:MM:SS (hours may exceed 24 for service after midnight), dates must be YYYYMMDD, and event_sequence must be a non-negative whole number.
Interpretation: permissive: GTFS time syntax with hours beyond 24:00:00 is accepted, though the spec's Time type does not state it explicitly (spec-questions #5).
Spec reference: https://tods-transit.org/spec/
Severity: ERROR.
Two rows in a TODS-specific file share the same primary key (run_events: service_id + run_id + event_sequence; vehicles: vehicle_id; vehicle_assignments: date + block_id + service_id). Consumers cannot tell the rows apart.
Spec reference: https://tods-transit.org/spec/
Severity: ERROR. Needs a companion GTFS feed.
service_id in vehicle_assignments.txt is required when the same block_id is used by more than one service. Without it, the assignment cannot be matched to a single block.
Interpretation: per-row reading: fires only for rows whose block_id is ambiguous, not for every row once any block is shared (spec-questions #8).
Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt
Severity: WARNING.
A value is padded with spaces. IDs with stray spaces will not match the records they reference, and consumers are not required to trim them.
Interpretation: strict: values are compared exactly; the spec defines no trimming rule, so padded example values are flagged rather than silently trimmed (spec-questions #3).
Example: Before: stop_id value is " 1234 ". After: trim on export — 1234.
Spec reference: https://tods-transit.org/spec/
Severity: ERROR.
A row in employee_run_dates.txt names a (service_id, run_id) pair that has no events in run_events.txt. The assignment cannot be matched to a run.
Spec reference: https://tods-transit.org/spec/#employee_run_datestxt
Severity: WARNING.
A file references another file that is not in the package (or, for GTFS targets, not in the companion feed), so those references could not be validated.
Spec reference: https://tods-transit.org/spec/
Severity: ERROR.
A row in vehicle_assignments.txt names a vehicle_id that is not defined in vehicles.txt.
Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt
Severity: ERROR.
A supplement file contains a delete (TODS_delete=1) and another row with the same primary key. The spec prohibits this because supplement rows are not processed in order, so the result is undefined.
Spec reference: https://tods-transit.org/spec/#supplement-files
Severity: WARNING.
A supplement file contains multiple non-delete rows with the same primary key. Supplement rows are not processed in order, so which values win is undefined.
Spec reference: https://tods-transit.org/spec/#supplement-files
Severity: WARNING.
A supplement row sets TODS_delete=1 and also fills in other fields. The spec says the row is removed and the other values are ignored.
Spec reference: https://tods-transit.org/spec/#supplement-files
Severity: ERROR. Needs a companion GTFS feed.
A run event names a trip_id that is not in the companion GTFS trips.txt after supplements are applied.
Example: Before: run_events.txt row has trip_id=T-1042, but the companion trips.txt was re-exported without T-1042. After: re-export the companion GTFS alongside the TODS feed, or update trip_id to the current trips.txt value.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: ERROR. Needs a companion GTFS feed.
A run event names a service_id that is not defined in the companion GTFS calendar.txt or calendar_dates.txt after supplements are applied.
Example: Before: run_events.txt uses service_id=WKDY-OLD, but calendars were regenerated with service_id=WKDY-2026. After: update the run event's service_id, or define WKDY-OLD in calendar_supplement.txt.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: ERROR. Needs a companion GTFS feed.
A run event's start_location or end_location is not in the companion GTFS stops.txt after supplements are applied.
Example: Before: run_events.txt row has start_location=STOP-99, but stops.txt renumbered it to STOP-0099. After: update start_location/end_location to the current stop_ids, or add the stop via stops_supplement.txt.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: ERROR. Needs a companion GTFS feed.
A run event sets both block_id and trip_id, and the trip's block_id in the supplemented GTFS feed is different. The spec requires the two to match when both are set.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: ERROR. Needs a companion GTFS feed.
A vehicle assignment names a block_id that no trip uses in the companion GTFS feed after supplements are applied.
Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt
Severity: ERROR. Needs a companion GTFS feed.
A vehicle assignment names a service_id that is not defined in the companion GTFS calendars after supplements are applied.
Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt
Severity: WARNING. Needs a companion GTFS feed.
A supplement row sets TODS_delete=1 but no row with that primary key exists in the companion GTFS file. Nothing is deleted; this usually means the ID is wrong or the GTFS feed changed.
Spec reference: https://tods-transit.org/spec/#supplement-files
Severity: ERROR. Needs a companion GTFS feed.
A supplement row names a route, service, trip, or stop that is not in the supplemented GTFS feed (for example, a trip added by trips_supplement.txt with a route_id that exists nowhere). The merged feed would not form valid GTFS.
Example: Before: trips_supplement.txt adds a trip with route_id=RT-77, but no such route exists in routes.txt or routes_supplement.txt. After: use an existing route_id, or add RT-77 to routes_supplement.txt.
Spec reference: https://tods-transit.org/spec/#supplement-files
Severity: WARNING. Needs a companion GTFS feed.
A run event works a trip end to end (trip_id set, the matching mid_trip flag not 1), but its start_location is not the trip's first stop, or its end_location is not the trip's last stop, in the supplemented stop_times.txt.
Interpretation: the spec says these locations 'should' be the trip endpoints, so a mismatch is a warning; skipped for mid-trip events and for trips with no stop_times.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: WARNING. Needs a companion GTFS feed.
A run event works a trip end to end (trip_id set, the matching mid_trip flag not 1), but its start_time is not the trip's first scheduled departure, or its end_time is not the trip's last scheduled arrival, in the supplemented stop_times.txt.
Interpretation: the companion of TODS-W315 for time: a run event claiming to work a whole trip should span the trip's scheduled times, so a mismatch is a warning; skipped for mid-trip events, for trips with no stop_times, and when either time is unparseable.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: ERROR.
A run event's end_time is earlier than its start_time. Equal times are fine (the spec allows zero-duration events such as a report time); for work past midnight, use hours of 24 or more rather than wrapping around.
Interpretation: the spec is silent on end<start; this treats it as an error and equal times as valid (spec-questions #5).
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: ERROR.
Within one run, two events that both reference trips overlap in time. The spec prohibits this: an employee cannot be on two trips at once. Touching end-to-start (zero-minute overlap) is allowed.
Spec reference: https://tods-transit.org/spec/#event_sequence-and-event-times
Severity: WARNING.
Within one run, event_sequence does not increase with start_time. The spec says sequence values should increase throughout the day; out-of-order values usually mean the sequence or a time is wrong.
Spec reference: https://tods-transit.org/spec/#event_sequence-and-event-times
Severity: WARNING.
An employee is assigned to two runs on the same date whose events overlap in time. Real schedules have legitimate exceptions, so this is a warning, not an error.
Spec reference: https://tods-transit.org/spec/#employee_run_datestxt
Severity: ERROR. Needs a companion GTFS feed.
A run event works a trip whose service is different from the run's service, and the run's service operates on dates the trip's service does not. The spec requires the run's dates to be a subset of the trip's dates.
Spec reference: https://tods-transit.org/spec/#service_id-crew-schedules-and-trip-schedules
Severity: WARNING. Needs a companion GTFS feed.
An employee_run_dates.txt row assigns a run on a date when the run's service_id does not operate, according to the supplemented calendars.
Spec reference: https://tods-transit.org/spec/#employee_run_datestxt
Severity: WARNING. Needs a companion GTFS feed.
A vehicle_assignments.txt row names a service_id and a date when that service does not operate, according to the supplemented calendars.
Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt
Severity: WARNING.
Two rows in employee_run_dates.txt are exactly identical (same date, service, run, and employee). Multiple employees per run are fine; the same employee twice is usually an export bug.
Interpretation: permissive: the spec's 'Primary Key: *' is read as not forbidding an exact duplicate row, so this is a warning rather than an error (spec-questions #6).
Spec reference: https://tods-transit.org/spec/#employee_run_datestxt
Severity: WARNING.
Within one run, an event ends at one location but the next event in event_sequence order starts somewhere else. An operator is one person who cannot teleport, so a gap usually means a missing deadhead event or a wrong location. Events with a blank endpoint are skipped.
Interpretation: the spec does not state this explicitly, but a run is a continuous tour of duty; legitimate exceptions exist (so a warning), and adjacencies with a blank location are not flagged.
Spec reference: https://tods-transit.org/spec/#event_sequence-and-event-times
Severity: INFO. Needs a companion GTFS feed. Opt-in: off by default, enable with --enable coverage or --enable TODS-I501.
Some trips in the companion GTFS feed are never referenced by a run event, so no crew work is described for them. This is informational: not every trip must appear in run_events.txt, but wide gaps can mean an incomplete export.
Spec reference: https://tods-transit.org/spec/#run_eventstxt
Severity: INFO. Needs a companion GTFS feed. Opt-in: off by default, enable with --enable coverage or --enable TODS-I502.
Some blocks in the companion GTFS feed have no row in vehicle_assignments.txt, so no vehicle is assigned to operate them. Informational: vehicle assignments are optional, but unassigned blocks may signal an incomplete export.
Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt
Severity: INFO. Opt-in: off by default, enable with --enable advisory or --enable TODS-I601.
A run is on duty for a long continuous span with no event whose type names a break, lunch, or meal. Advisory only: break modelling varies by agency and labor agreement, so this is never an error.
Interpretation: advisory: 'break' detected by event_type containing break/lunch/meal
Spec reference: https://tods-transit.org/spec/#run_eventstxt