Skip to main content
Back to Racey School
8 min read
League admins and race directors

Results CSV Import Guide

Column reference, validation rules, and troubleshooting for the Results import wizard. Templates included.

Build a valid results CSV from scratch or from an iRacing export
Diagnose the most common validation errors quickly
Know which columns are required vs. optional
Use this guide during beta
1
Import a real round's results from a CSV end-to-end
2
Trigger and resolve at least one validation error to test the wizard
3
Verify multiclass car-class mapping behaviour on your league
Open quick reference

A reference for the Results import wizard. Covers the column list (required vs optional), the validation errors you can hit, and how to fix the rows that fail.

The Racey results importer accepts CSV files in a fixed shape. The wizard at League → Results → Import auto-detects most common header variants (iRacing exports work out of the box), so you usually do not need to rename columns by hand. This guide is the source of truth when auto-detection misses something or when you are building a CSV from scratch.

Quick start

Two ways to grab a template:

  1. Empty CSV/templates/results.csv. Header row only, in canonical order.
  2. Empty CSV pre-filled with your rosterGET /api/leagues/[leagueId]/import-template?seasonId=[seasonId]. Adds one row per approved registration with the driver name pre-populated and other fields blank. Useful when you already know the field for the round and just need to fill in finishing positions.
  3. Sample CSV with realistic data/templates/results-sample.csv. Header row plus ten plausible rows (multiclass GT3+GT4, with a DNF and a DSQ) so you can see the shape.

Save your filled file as UTF-8 CSV with a comma delimiter (the default in Excel, Google Sheets, and Numbers). The importer also accepts JSON if you are pulling from an API; this guide is CSV-focused.

Column reference

The importer recognizes thirteen columns. Auto-detection matches on common header variants — for example, Driver Name, name, display_name, and driver all map to the same field — so do not panic if your existing export uses different labels.

Five columns are required for the import to succeed: every row needs a finishing position, a driver name, a start position, a lap count, and an incident count. Everything else is optional and can be left blank.

HeaderFieldRequiredNotes
PositionFinish positionYesInteger, 1-indexed. Must be at least 1.
Driver NameDisplay nameYesTrimmed; non-empty after trim.
External IDCross-system identifierNoiRacing cust_id, league member ID, etc. Used to remember driver mappings between imports.
Car NumberCar numberNoString. Leading zeros preserved.
Start PositionGrid positionYesInteger ≥ 1. iRacing 0-indexed positions are auto-bumped to 1.
Laps CompletedLaps completedYesInteger ≥ 0.
Laps LedLaps ledNoInteger ≥ 0. Defaults to 0.
IncidentsIncident pointsYesInteger ≥ 0.
IntervalTime gap to leaderNoString — +3.215 or +1 lap. DNF/DSQ rows often leave this blank.
Fastest LapFastest lap timeNom:ss.sss like 2:18.412, raw seconds, or iRacing tenths-of-ms.
Average LapAverage lap timeNoSame formats as fastest lap.
Finish StatusFinal statusNoOne of running, dnf, dsq, dns. Numeric iRacing reason_out_id is also recognized (0 = running, 29 = dsq, anything else non-zero = dnf). Defaults to running.
Car ClassClass name for multiclassNoMust match a class name configured for the season (case-insensitive). Unrecognized class names import the row but leave class assignment empty.

A handful of additional columns are recognized by auto-detection but are not in the canonical template — Team, iRating, and a qualifying lap time. These are persisted on the result row when present but are not required and are not part of the static template.

Required field details

The wizard's mapping step blocks Next if any of the five required fields is unmapped. The exact missing-field labels you will see come from FIELD_LABELS:

  • Finish Position
  • Driver Name
  • Start Position
  • Laps Completed
  • Incidents

If your CSV does not contain start positions, fill the column with the same value as Position for each row — the importer treats start = finish as a valid (if unusual) outcome.

Lap time formats

The parser accepts three formats interchangeably for Fastest Lap and Average Lap:

  • m:ss.sss strings — 2:18.412 becomes 138.412 seconds.
  • Plain seconds — 138.412 is taken as-is.
  • iRacing tenths-of-ms — any number greater than 10000 is divided by 10000, so 1384120 becomes 138.412 seconds.

Sentinel values are treated as "no time set":

  • Empty string, 0, 0:00.000
  • -1
  • 59:59.999 (iRacing's "did not set a time" sentinel)

Finish status normalisation

The importer normalises Finish Status aggressively because iRacing exports use numeric reason codes and other tools use strings. All of these become running:

  • empty / blank
  • running, finished, 0

DNF synonyms (become dnf): dnf, did not finish, ret, retired, disconnected, any other non-zero numeric reason code (except 29).

DSQ synonyms (become dsq): dsq, disqualified, dq, numeric 29.

DNS synonyms (become dns): dns, did not start.

Anything else falls back to running. If you want a row to count as DNF, use one of the strings above.

Wizard flow

After upload, the wizard walks you through four steps:

  1. Upload — pick a target session and drop or paste your file. Caps: 5 MB and 1000 rows per import.
  2. Map Columns — auto-detected mappings are pre-selected. Override anything that looks wrong. The Next button is gated on all five required fields being mapped.
  3. Resolve Drivers — every driver name (and external ID, when present) is matched against your league roster. You confirm fuzzy matches or create an "external driver" row for guests who have no Racey account.
  4. Review & Import — final preview with a count of importable rows and skipped rows. Click Import to apply.

Driver mappings (external ID → user) are remembered for future imports unless you uncheck the toggle.

Validation errors and how to fix them

Errors fall into three layers: parse errors (CSV cannot be read), mapping errors (rows can be read but key fields are missing or invalid), and import errors (rows passed parsing but the server rejects them).

Parse errors

MessageCauseFix
File is emptyThe pasted text or file is empty after trimming.Paste the data or re-upload.
CSV file is empty or has no data rowsHeader row only, no rows below.Add at least one data row.
CSV file has no column headersThe parser could not detect a header row.Confirm the first line contains comma-separated header names, not data.
Pasted data is too large — max 5 MBPaste exceeded the 5 MB cap.Split the file or upload as a .csv instead of pasting.
Too many rows — max 1000 per import (got <n>)Your file has more than 1000 data rows.Split the file by class or session. The cap mirrors the server-side MAX_IMPORT_ROWS constant.
Pasted data is too large toastSame as above (file upload variant).Same fix; the limit is identical for paste and upload.

For unsupported file types you get an "Unsupported file type" toast; the importer accepts .csv, .json, and .txt.

Mapping warnings (per row)

These appear in the Review step. The row is dropped from the import but the rest of the file proceeds.

WarningCauseFix
Row N: Invalid or missing position "<value>"The mapped position column was empty, non-numeric, or less than 1.Fix the position cell. iRacing's 0-indexed export is auto-bumped, but null or text is not.
Row N: Missing driver nameThe mapped driver-name column was empty after trimming.Fill in a name. The importer cannot match an anonymous row.
Position N appears X timesTwo or more rows share the same finish position.In multiclass races this is expected and informational. In single-class races it indicates a data error — fix the position cell.

Import errors (server-side)

The server validates the final payload one more time and may reject the whole import:

MessageCauseFix
Session not foundThe session ID no longer exists.Reload the results page and pick a fresh session.
Cannot import results for a cancelled round. Reschedule or reactivate the round first.The target round is marked cancelled.Reactivate the round before importing.
Cannot import results for a postponed round. Reschedule or reactivate the round first.Same as above for postponed rounds.Reschedule the round, then re-import.
No results with resolved drivers to importEvery row was either skipped or unresolved.Map drivers in the Resolve step or create external-driver rows for guests.
Forbidden: results import requires appropriate permissionsYou do not have results.import for this league.Ask a league admin to grant the permission.
Results for this round are locked. Reopen the result set before making changes.The round's results were already finalised.Unlock the result set in the round admin before re-importing.
Cannot import results for drivers who are not approved for this season: <ids>One or more rows resolve to a Racey user who is not an approved entrant for the season.Approve the registrations, or create external-driver rows for the unregistered users.
Too many imports. Please wait a minute and try again.You hit the per-user write rate limit (30 / minute).Wait one minute.
At least one result is requiredThe validated payload had zero rows.Confirm your file has data rows below the header.
At most 1000 results per importServer enforcement of MAX_IMPORT_ROWS.Split the file.
Failed to import resultsGeneric catch-all when the database transaction fails.Retry. If the failure is reproducible, check server logs or contact support.

Common mistakes

  • Empty rows at the bottom of the file. Excel often appends blank rows. The parser skips empty lines, but rows with whitespace in one cell are kept and then fail row-level validation. Trim the file before uploading.
  • Header capitalisation. Auto-detection is case-insensitive, but if you handcraft the file, match the canonical headers in the table above for predictability.
  • Lap time stored as Excel duration. When Excel detects a time-like value it sometimes converts to a serial fraction (e.g. 0.0958809...). Format the column as text before pasting your times in.
  • Comma in the driver name. Wrap the cell in double quotes ("Smith, John"). All sample rows in the templates do this where applicable.
  • DNF rows with no laps. A driver who didn't start a lap can have Laps Completed = 0 and Finish Status = dnf — both valid. The row will still import as long as Position is set.
  • Unrecognized class names. The class column is matched case-insensitively against the season's configured car classes. A typo silently leaves the row's class as null — check your season's class names before importing.