# The import report

Read what every index run took in and what it left out: each row and value with its reason, and each setting it derived.

Every [index run](/docs/reference/glossary#index-run) reports what it took in from the [catalog](/docs/reference/glossary#catalog) and what it left out, each with its reason. So no row goes missing unseen, and a broken one never takes the rest of the catalog with it.

**In the panel:**

**Releases** lists the **Index runs**, newest first, each with its state, the entries it indexed and how many it **Left out**. **Report** on a run's row opens what it read and left out: each problem with its row, the entity, the column or field, and why.

**Through the API:**

`GET /api/v1/index-runs` lists the runs newest first, each with its report. Here are the latest run's counts:

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/index-runs \
  | jq -c '.data[0] | {state} + (.report | {rows, entities, rejected})'
```

```json title="Answer: 200 · 15 ms"
{"state":"succeeded","rows":40,"entities":39,"rejected":1}
```

The home store's run read 40 rows, made 39 [entities](/docs/reference/glossary#entity) live and left one row out.

**Reference:** [`GET /api/v1/index-runs`](/docs/reference/management-api#list-index-runs) · [`GET /api/v1/index-runs/{index_run}`](/docs/reference/management-api#show-index-run) · [`RunReport`](/docs/reference/management-api#RunReport)

## Rows left out

A row with a broken field is left out whole, with its variants. The report groups the rows by what is wrong, and lists the first ten of each:

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/index-runs \
  | jq -c '.data[0].report.rejections[] | {code, count}, (.examples[] | {row, id, pointer, message})'
```

```json title="Answer: 200 · 12 ms"
{"code":"invalid_field","count":1}
{"row":27,"id":"TEPPICH-SILO","pointer":"/variants/1/price","message":"Invalid type: string \"249,00 €\", expected a JSON number."}
```

Row 27 is the rug `TEPPICH-SILO` (Teppich: rug), whose second variant writes its price as text. The `pointer` names the field, and `row` is numbered as the file counts it. In an export, each example also names its `column`.

A value that does not fit its [attribute](/docs/reference/glossary#attribute) is dropped instead, and its entity kept. Those are counted apart, under `values.rejected`. Before an export goes live, its import lists the same problems ([Importing and mapping](/docs/importing)).

**Reference:** [`rejections`](/docs/reference/management-api#RunReport.rejections) · [`RejectionGroup`](/docs/reference/management-api#RejectionGroup) · [`values.rejected`](/docs/reference/management-api#ValuesReport.rejected)

## Settings it derived

The run derives each file the [release](/docs/reference/glossary#release) leaves out from the catalog, and gives every setting its reason:

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/index-runs \
  | jq -c '.data[0].report.defaults.reasons[] | {setting, file, reason}'
```

```json title="Answer: 200 · 12 ms"
{"setting":"product.no_typos.model_number","file":"types.json","reason":{"by":"few","values":0}}
{"setting":"product.no_typos.gtin","file":"types.json","reason":{"by":"few","values":0}}
```

The home store's release writes all of these files, but its `types.json` leaves open which identifiers a search must match exactly. So the run decided: the catalog holds no model numbers or GTINs, too few to tell whether each names one product, so typos still find them.

A catalog sent with an empty release derives far more, such as why "Farbe" (color) became a color filter ([Your own catalog](/docs/your-own-catalog)).

**Reference:** [`defaults`](/docs/reference/management-api#RunReport.defaults) · [`Derived`](/docs/reference/management-api#Derived)

## Values attributes.json does not list

A value the catalog spells that `attributes.json` does not list becomes a value of its own, as the catalog spells it. The report names each one:

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/index-runs \
  | jq -c '.data[0].report.values | {new, ungrouped}, (.derived[] | {attribute, label, groups})'
```

```json title="Answer: 200 · 12 ms"
{"new":4,"ungrouped":1}
{"attribute":"color","label":"Klarglas","groups":["clear"]}
{"attribute":"color","label":"Rauchglas","groups":null}
{"attribute":"features","label":"abnehmbarer Bezug","groups":null}
{"attribute":"material","label":"Polypropylen","groups":null}
```

"Klarglas" (clear glass) is a color the built-in colors know, so it shows under clear. "Rauchglas" (smoked glass) holds no color word, so it stays without a group. The other two, "abnehmbarer Bezug" (removable cover) and "Polypropylen" (polypropylene), need none. List a value in `attributes.json` to give it the label and group you want ([Types and attributes](/docs/types-and-attributes)).

**Reference:** [`values`](/docs/reference/management-api#RunReport.values) · [`DerivedValue`](/docs/reference/management-api#DerivedValue)

## Index run states

A run builds fresh indexes beside the live ones and swaps them in, so shoppers never see half a catalog:

- `queued`: it waits for the indexer.
- `running`: it builds the indexes, and `progress` says how far it got.
- `succeeded`: it is live, and searches read its snapshot and release.
- `failed`: `error` says why, and nothing it built went live.
- `superseded`: a newer run took its place before it went live.

<Callout type="info">
    A failed run changes nothing shoppers see: the last run that succeeded stays live. A file in which no row can be
    indexed fails this way.
</Callout>

**Reference:** [`state`](/docs/reference/management-api#IndexRun.state) · [`error`](/docs/reference/management-api#IndexRun.error) · [`progress`](/docs/reference/management-api#IndexRun.progress)

## Next

- [Importing and mapping](/docs/importing): see the problems before an export goes live, and correct how it is read.
- [Formats we read](/docs/formats): the files an index run reads, and OrbSearch JSON Lines.
- [Releases](/docs/releases): publish, roll back, and the runs they queue.
