# Import files in the console

URL: /collect/import-files

Add one run's flight log and companion evidence from your browser. Foxborne recognizes each format, computes every file's SHA-256 before it uploads and opens the new run as soon as you import.



Use **Import files** when a run's files are on your machine. That can be a flight log copied from the SD card, a journal export, collector samples or a receive log. The page checks each file's size and format, computes its SHA-256 in your browser and creates the run in one step.

## Before you start [#before-you-start]

* You need the **Investigator** or **Admin** role. They are the two roles with the **Import runs and files** permission.
* Each file must be a format the **Import files** page takes: PX4 ULog (`.ulg`), a journalctl JSON export, collector JSONL or receiver JSONL. See [Supported file formats](/collect/formats).
* Each file must fit under the import limit, 250 MB by default. An admin can raise it to 1 GB or 4 GB under **Settings**, **Import**, **Largest file**.
* Export the companion journal with `journalctl -o json`. [journalctl JSON exports](/collect/formats/journald) has the full command.

## Import a run [#import-a-run]

<Steps>
  <Step title="Open Import files">
    Select **Import files** in the sidebar, under **Investigate**. The **Import files** button at the top of the **Runs** and **Incidents** lists opens the same page.
  </Step>

  <Step title="Add the files">
    Drag the files onto **Drop files here**, or select **Choose files** and pick several at once. The drop zone states what it takes: &#x2A;*PX4 .ulg, journalctl JSON export, collector JSONL or receiver JSONL. Up to 250 MB per file.**

    To try the page before you use real files, **Use sample files** adds an example flight log, journal export and collector samples.
  </Step>

  <Step title="Wait for each file to show Ready">
    The **Files** panel appears under the drop zone and lists each file with a status chip and a count such as **2 of 3 ready**. A file moves from **Validating** to **Hashing** to **Ready** while its detail line fills in:

    * The format, the size and what Foxborne found, for example **PX4 ULog, version 1** with **Magic bytes verified**.
    * Once hashed, a second line with the first 12 and last 4 hex characters of the SHA-256, followed by **computed in your browser**.

    A file that fails a check shows **Quarantined** or **Rejected**, with the reason in place of its detail line. Remove any file with the × at the end of its row. Once a file is ready, the right of the panel header says where the run's start time comes from: **Start time comes from the flight log**, or **No flight log, so the companion clock is used**.
  </Step>

  <Step title="Describe the run, if you want to">
    Select **Run details** at the top right of the page. The drawer opens with the note &#x2A;*Optional. Foxborne detects the vehicle from the flight log and labels the run by date if you leave these empty.**

    | Field                | What to enter                                                                                                                                                                    |
    | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Vehicle**          | Leave **Detect from the flight log**, and Foxborne matches the vehicle from the MAVLink system ID in the flight log. Or pick the vehicle, for example **UAS-04, Q4 recon quad**. |
    | **Run label**        | A name the team will recognize, for example **North field grid D**. Left blank, the run is labeled **Imported** and the date, such as **Imported 26 Sep**.                       |
    | **Notes (optional)** | Wind, payload, what the operator saw. Notes are saved as an annotation with your name and are never treated as evidence.                                                         |

    When Foxborne detects the vehicle, the hint says how, for example &#x2A;*Detected UAS-04 from sys\_id 4 in the flight log.** The drawer keeps what you enter when you close it with **Done**. Its footer counts the files that are ready, such as **3 files ready**.
  </Step>

  <Step title="Select Import">
    **Import** sits at the top right of the page, beside **Run details**, and the **Run details** drawer has the same button in its footer. It counts the files that are ready, for example **Import 3 files**, and stays disabled until one is. Only files marked **Ready** go into the run.
  </Step>
</Steps>

<Callout type="marking" title="Positions and storage">
  Flight logs contain positions, and exported reports remove coordinates unless the exporter turns them back on.

  The **Run details** drawer names where the files go, under **Where the files go**. In the example deployment it reads &#x2A;*Files go to your own storage in AWS GovCloud (US-West). Nothing leaves your network.**
</Callout>

## How Foxborne recognizes a file [#how-foxborne-recognizes-a-file]

Foxborne identifies a file by its content, not its name. It checks the size first, then reads the first 4,096 bytes and tests them in the order below. The first match decides.

| Check                                                                                               | Result on the row                                                                                                                                 |
| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Larger than the import limit                                                                        | **Rejected**: &#x2A;*Larger than the 250 MB limit. Ask an admin to raise it for this import.**                                                    |
| The first seven bytes are `55 4C 6F 67 01 12 35`, which is "ULog" then `0x01 0x12 0x35`             | **PX4 ULog, version 1**, with **Magic bytes verified**. The version is the eighth byte.                                                           |
| The text contains `__REALTIME_TIMESTAMP`                                                            | **journalctl JSON export**, with **Journal fields found**                                                                                         |
| The text contains `"recv_utc"`                                                                      | **Receiver JSONL**, with **Receive records found**                                                                                                |
| The text contains `"boot_id"` or `"rss_kib"`                                                        | **Collector JSONL**, with **Process samples found**                                                                                               |
| The name ends in `.ulg`, but the magic bytes are missing                                            | **Quarantined**: &#x2A;*Named .ulg, but the ULog magic bytes are missing. The file may be corrupt or not a PX4 log.**                             |
| A text file of up to 8 MB with the same columns as a saved parser                                   | Read with that parser: *format name*, **parsed with a saved parser**, with the record count and its clock                                         |
| Any other text file of up to 8 MB with a column or key that holds times, while the AI models are on | **New format**: **A text log in a format Foxborne does not read yet**, with the line count and the time column, and a **Propose a parser** button |
| Anything else                                                                                       | **Rejected**: &#x2A;*Not a format Foxborne reads. Expected PX4 ULog, journalctl JSON, collector JSONL or receiver JSONL.**                        |

Only the sixth check looks at the file name. The two text checks read CSV, tab, semicolon or pipe separated columns and JSON Lines. Once a format matches, the browser reads the whole file and computes its SHA-256 with the Web Crypto API. A file the browser cannot read shows **Rejected** with &#x2A;*The file could not be read.**

## Import a format Foxborne does not read yet [#import-a-format-foxborne-does-not-read-yet]

A radio's status export, a payload log or a test rig's CSV has no parser in Foxborne. When the file is text with a time on every line, the [AI models](/concepts/ai-models) propose a parser for it instead of rejecting it. The parser runs over the whole file before anyone saves it, and saving it is an admin's decision.

**Use sample files** adds such a file to the three samples: `mesh0-radio-status.csv`, a mesh radio's status log.

<Steps>
  <Step title="Open the proposal">
    The file's row shows **New format** with &#x2A;*A text log in a format Foxborne does not read yet: 180 lines, with times in the time column.** Select **Propose a parser**.
  </Step>

  <Step title="Check the proposed parser">
    The dialog **Propose a parser** shows **First lines**, the first six lines of the file, then **Proposed parser**, one row per column with an example value:

    | Column                             | Read as                           | Example                 |
    | ---------------------------------- | --------------------------------- | ----------------------- |
    | `time`                             | **Time (date and time, no zone)** | 2026-09-26 08:12:03.412 |
    | `node`                             | **Label**                         | mesh0-ugv04             |
    | `link`                             | **What happened**                 | UP                      |
    | `rssi_dbm`, `snr_db`, `tx_retries` | **Measurement**                   | -68, 30, 1              |
    | `usb`                              | **Label**                         | attached                |

    A column can be read as **Time**, **What happened**, **Measurement**, **Label** or **Leave out**. Change any of them before you save.
  </Step>

  <Step title="Name it and choose its clock">
    **Format name** starts from the file name. **Clock** is **Its own clock, align later** when the times carry no zone, or **UTC** when they do. Either way the file gets no bound and no before or after claim against other sources until it is aligned from matching events, because how well the device kept time is not in the file.
  </Step>

  <Step title="Read the parser's run over every line">
    **Run over every line** updates with each change. For the sample it reads:

    * **180 of 180 records read.** Lines it cannot read are listed by number and stay in the original file.
    * **Times never go backwards.**
    * **Covers 08:12:03 to 08:15:02 on its own clock, 2 min 59 s.**
    * **12 measurements are empty and will read as not recorded, never as zero.**
    * **The file stays on its own clock. No before or after claim is made against other sources until it is aligned from matching events.**
  </Step>

  <Step title="Save the parser">
    Select **Save parser and add the file**. The footer notes **Only admins can save a parser**. Foxborne confirms with &#x2A;*Mesh0 radio status saved. Files like this one are read from now on.**, and the row turns **Ready**: **Mesh0 radio status, parsed with a saved parser**, with **180 records, own clock** and the file's SHA-256.
  </Step>
</Steps>

On the run, the file is listed under **Source files** as a **Mapped log** on **The device’s own clock**, with **None until aligned from matching events** and **No anchor** for its bound. The audit log records **Saved parser**, and **Settings**, under **Import**, lists it after the built-in formats as **Saved parsers: Mesh0 radio status**. Later files with the same columns are read with the saved parser, whether or not the models are on.

## Check the result [#check-the-result]

The run opens as soon as you select **Import**. A toast confirms it with the file count and the new run ID, for example **Importing 3 files as R-0937**.

* The run shows **Parsing**, a progress bar and the current step. The steps are **Validating type, size and schema**, **Hashing originals**, **Parsing the flight log**, **Parsing journal and samples**, **Aligning clocks** and **Running rules**.
* The **Clock** chip reads **Pending** until the clocks are aligned, and **Runs** in the sidebar counts **1 parsing**.
* **Source files** lists each file under &#x2A;*Manual upload. Hashed on arrival and stored unmodified.** Compare each file's **SHA-256** with the hash your browser showed.
* When parsing ends, the status changes to **Complete** or **Partial**, and the **Clock** chip shows the bound, such as **Aligned ±46 ms**. **Import job**, at the top right of the run page, then opens each step with its time.
* Notes you wrote in **Run details** show on the run page under **Notes**, with your name and the time.
* The audit log records **Imported run** with the run ID and a detail such as **3 files, manual upload**.

## Troubleshoot [#troubleshoot]

* **Larger than the 250 MB limit. Ask an admin to raise it for this import.** An admin can raise **Largest file** under **Settings**, **Import**, to 1 GB or 4 GB; oversized files are refused with a reason, never truncated.
* **Named .ulg, but the ULog magic bytes are missing.** The copy is damaged, or the file is not a PX4 log. Copy it from the SD card again and add the new copy.
* **Not a format Foxborne reads.** Check that you picked the right file. A text log with a time on every line gets **Propose a parser** instead, while the AI models are on. A journal exported in journalctl's default `short` format carries no field names, so export it again with `-o json`.
* **The detected vehicle is wrong.** Open **Run details** and pick the vehicle in **Vehicle** before you select **Import**.

For statuses a run can show after import, such as **Quarantined**, **Rejected** and **Partial**, see [Import statuses and fixes](/collect/troubleshoot-imports).

## Next [#next]

* [Check a run](/investigate/runs) walks through the run page once parsing ends.
* [Connect a storage source](/collect/sources) so files arrive without an upload.
* [Supported file formats](/collect/formats) lists what each format carries and the parser that reads it.
