deepset-ai/haystack · error · RuntimeError

CSVToDocument(row): failed to process row {i} for {source}:

Error message

CSVToDocument(row): failed to process row {i} for {source}: {e}

What it means

Each row is converted individually; if building a Document from a row raises (e.g. the content cell is missing/None), the component wraps the error in a RuntimeError identifying the row index and source, and stops immediately instead of skipping the row.

Source

Thrown at haystack/components/converters/csv.py:190

            except Exception as e:
                raise RuntimeError(f"CSVToDocument(row): could not parse CSV rows for {source}: {e}") from e

            # Validate header contains content_column; strict error if missing
            header = reader.fieldnames or []
            if content_column not in header:
                raise ValueError(
                    f"CSVToDocument(row): content_column='{content_column}' not found in header "
                    f"for {source}. Available columns: {header}"
                )

            # Build documents; if a row processing fails, raise immediately (no skip)
            for i, row in enumerate(reader):
                try:
                    doc = self._build_document_from_row(
                        row=row, base_meta=merged_metadata, row_index=i, content_column=content_column
                    )
                except Exception as e:
                    raise RuntimeError(f"CSVToDocument(row): failed to process row {i} for {source}: {e}") from e
                documents.append(doc)

        return {"documents": documents}

    # ----- helpers -----
    def _safe_value(self, value: Any) -> str:
        """Normalize CSV cell values: None -> '', everything -> str."""
        return "" if value is None else str(value)

    def _build_document_from_row(
        self, row: dict[str, Any], base_meta: dict[str, Any], row_index: int, content_column: str
    ) -> Document:
        """
        Build a ``Document`` from one parsed CSV row.

        :param row: Mapping of column name to cell value for the current row
            (as produced by ``csv.DictReader``).
        :param base_meta: File-level and user-provided metadata to start from

View on GitHub (pinned to e318778c9b)

Solutions

  1. Open the message's row index in the source CSV and fix/clean that row.
  2. Pre-validate the CSV so every row has all header columns (pad short rows).
  3. Use restkey-aware preprocessing or fill missing content cells with a default.
  4. Convert the file with a spreadsheet tool to normalize fields.

Example fix

// before
# rows with missing trailing cells cause: failed to process row 12
result = csv_conv.run(sources=[f], content_column="text")
// after
import csv, io
rows = list(csv.reader(io.StringIO(f.data.decode("utf-8")))); header = rows[0]
normalized = [dict(zip(header, r + [""] * (len(header) - len(r)))) for r in rows[1:]]
# feed normalized data instead
Defensive patterns

Strategy: validation

Validate before calling

def validate_ragged_rows(rows, header, content_col):
    for i, r in enumerate(rows):
        if len(r) < len(header):
            raise ValueError(f"Row {i} has {len(r)} fields, expected {len(header)}")
        if r[header.index(content_col)] in (None, ""):
            raise ValueError(f"Row {i} missing content in {content_col!r}")

Try / catch

try:
    result = conv.run(sources=[f], content_column=col)
except RuntimeError as e:
    if "failed to process row" in str(e):
        row_idx = int(str(e).split("row ")[1].split()[0])
        logger.error("Fix row %d in %s", row_idx, e)
    raise

Prevention

When it happens

Trigger: conversion_mode='row' where a row lacks the content_column key (short rows via restkey), or _build_document_from_row/_safe_value fails on unexpected row data.

Common situations: Ragged CSVs where some rows have fewer fields than the header; rows containing only the delimiter producing None cells; dirty exports with malformed trailing rows.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/2ddea40971286d5b. Report an issue: GitHub.