---
audience: developers
summary: When ingest fails, returns surprising warnings, or produces a lossy spec.
title: Ingestion
path: troubleshooting/ingestion
status: published
---


# Ingestion troubleshooting

`POST /v1/documents/ingest` rarely fails outright — its job is to extract what it can and report what didn't survive. So most "troubleshooting" here is about interpreting fidelity warnings rather than fixing 5xx responses. The cases below cover both.

For the warning catalogue and round-trip story, see [Concepts → Ingestion](/docs/scaiscribe/concepts/ingestion).

## 400 `INVALID_FORMAT` / unrecognised content type

**Symptom** — `ingest_document` returns 400 with `error.code = "INVALID_FORMAT"`.

**Cause** — The upload's content type didn't match a recognised format (DOCX, PPTX, XLSX). Either the `Content-Type` header was wrong or the bytes don't open as one of those formats.

**Fix** — Set the correct `Content-Type`:

| Format | Content-Type |
|---|---|
| `.docx` | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` |
| `.pptx` | `application/vnd.openxmlformats-officedocument.presentationml.presentation` |
| `.xlsx` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` |

The SDKs handle this for you when you pass `format="docx"|"pptx"|"xlsx"`.

## 400 `INGEST_READ_ERROR` / "failed to open"

**Symptom** — `error.code = "INGEST_READ_ERROR"` with a message like "failed to open .docx".

**Cause** — The bytes aren't a valid OOXML zip. Possible reasons:

1. **Corrupted upload.** Network truncation, or the bytes were modified in transit. Re-upload.
2. **Password-protected document.** ScaiScribe can't open encrypted .docx/.pptx/.xlsx. Decrypt first.
3. **`.doc`/`.ppt`/`.xls` (legacy binary format), not the modern OOXML variant.** Convert to the OOXML variant first (open + save-as in Word/LibreOffice).
4. **Macros-enabled format (`.docm`, `.pptm`, `.xlsm`).** Not supported. Save without macros (.docx/.pptx/.xlsx).

**Fix** — Confirm the source format. Convert if needed. Try opening the file in Word/LibreOffice manually; if that fails, the source itself is broken.

## Fidelity score is 0.0 or unexpectedly low

**Symptom** — Ingest succeeds but `fidelity.score = 0.0` (or near zero) and `warnings[]` has many entries.

**Cause** — The document used many features the ingester can't model: complex SmartArt, embedded objects, custom XML, advanced page layouts. ScaiScribe's spec model is simpler than full OOXML, and some documents map poorly.

**Fix** — Treat the result as a content extract, not a round-trip target. The body text and basic structure survive; visual fidelity will degrade on re-render. If round-trip matters, ask the author to provide the document as a ScaiScribe spec (or have them author it through ScaiScribe in the first place).

## `INGEST_PANDOC_*` warnings — what they mean

When pandoc is installed on the worker host, it runs alongside mammoth to surface higher-fidelity warnings. These warnings are **informational** — the visible text is still in the body; the warning tells you the structural metadata didn't survive.

| Code | What it means |
|---|---|
| `INGEST_PANDOC_FOOTNOTE_DETECTED` | Footnotes detected. Their text is inlined in the body where they were anchored. |
| `INGEST_PANDOC_MATH_DETECTED` | Math equations detected. Rendered as plain text. |
| `INGEST_PANDOC_CITATION_DETECTED` | Citation refs detected. Only the visible reference text survives. |
| `INGEST_PANDOC_DEFINITION_LIST_DETECTED` | Definition lists detected. Rendered as alternating paragraphs. |
| `INGEST_PANDOC_LINE_BLOCK_DETECTED` | Line blocks (poetry, addresses) detected. Line breaks lost. |

**If you don't see any `INGEST_PANDOC_*` warnings at all**, pandoc isn't installed on the worker host. The ingest still works — you just don't get these honest signals. Operator can install via `apt install pandoc` (Debian/Ubuntu).

## `INGEST_IMAGE_DROPPED` — where did my images go?

**Symptom** — Document has images; the resulting spec has no `image` elements; `INGEST_IMAGE_DROPPED` warning per image.

**Cause** — The DOCX ingester doesn't extract images to assets yet. The text around the image survives; the image itself is dropped.

**Fix** — After ingest, re-add the image elements via `scribe_add_image` (you'll need to upload the image bytes as an asset first via `POST /v1/assets`, then reference by `asset_id`).

The PPTX ingester does extract images. The XLSX path doesn't (images are rare in spreadsheets).

## `PPTX_INGEST_LAYOUT_UNMATCHED` — slides default to "content"

**Symptom** — Some slides come back with `layout: "content"` even though the source used a more specific layout, plus `PPTX_INGEST_LAYOUT_UNMATCHED` warning.

**Cause** — The slide's OOXML layout type doesn't match any layout in the active theme's master registry. Common when the source PPTX was authored against a different theme (Microsoft Office's defaults, Google Slides, etc.).

**Fix** — Either accept the `content` default (the slide elements still survive; just the layout association is approximate), or set the right layout per-slide after ingest via `scribe_set_slide_layout`. The full list of layouts available in a theme: see the theme's `pptx.masters[]` array.

## Ingested DOCX from ScaiScribe round-trips at fidelity < 1.0

**Symptom** — You ingested a DOCX that ScaiScribe itself produced, but `fidelity.score` is less than 1.0.

**Cause** — Almost certainly the `scaiscribe/breadcrumbs.json` part was stripped from the zip. The slow-path recovery handles `code_block`, `callout`, and `page_break` via mammoth styleMap, but `chart`, `toc`, and any other element types degrade to image/text approximations on the slow path.

**Diagnose** — Inspect the zip:

```bash
unzip -l my-doc.docx | grep scaiscribe
# expect:    1234  2026-06-14 08:42   scaiscribe/breadcrumbs.json
```

If the line is missing, the breadcrumb was stripped. Common culprits: third-party tools that rewrite the zip without preserving unknown parts (e.g. some PDF-conversion utilities, certain DRM wrappers).

**Fix** — Ingest the original file (with breadcrumb intact). If that's not possible, accept the degraded fidelity for the missing element types.

## Ingest hangs or times out

**Symptom** — `ingest_document` returns 202 with a job_id and the job never completes.

**Cause** — Same as render hangs: worker not running, or genuinely slow ingest (large complex PPTX is the typical case — 100+ slides with embedded media can take minutes).

**Fix** — Pass `sync=False` proactively for known-slow ingests. Poll the job.

## PPTX ingest extracts no text from slides

**Symptom** — Each slide comes back with `elements: []` even though the source has visible text.

**Cause** — The source PPTX used text in a way the OOXML walker doesn't recognise. Most common causes:

1. **Text inside SmartArt.** SmartArt has its own internal text model the walker doesn't traverse. The slide carries the SmartArt as `raw_ooxml` but the text isn't surfaced.
2. **Text inside grouped shapes.** Grouped shapes (a manually-aligned cluster) sometimes hide their text frames from the walker. Ungrouping in PowerPoint before ingest usually helps.
3. **Text inside text boxes overlapping placeholders.** The walker prefers placeholder text; if a slide uses non-placeholder text boxes for everything, it may miss them. Look for `INGEST_TEXTBOX_NON_PLACEHOLDER` warnings.

**Fix** — Re-author affected slides with proper placeholder usage, or accept the gap. PPTX is the format with the lowest ingest fidelity for a reason; spec-out the slides from scratch if you need full structural fidelity.

## XLSX ingest drops formulas

**Symptom** — Cells with formulas come back with their computed value but no `formula` field.

**Cause** — Actually `exceljs` does extract formulas — they appear in the spec as `cell.formula`. If you're seeing only values, possibilities:

1. The source workbook had formulas saved without cached values; the formula is there but reads as null.
2. You're inspecting the wrong field — check `cell.formula`, not `cell.value`.

**Fix** — Open the source in Excel; force a recalculation and re-save; re-ingest. Or scope the cell carefully and re-author.

## Where to next

- [Concepts → Ingestion](/docs/scaiscribe/concepts/ingestion) — the model and full warning catalogue.
- [Tutorials → Ingest + edit](/docs/scaiscribe/tutorials/ingest-and-edit) — end-to-end pattern.
- [Reference → API](/docs/scaiscribe/reference/api) — `/v1/documents/ingest` shape.
