deepset-ai/haystack · error
CSVToDocument(row): content_column=
Error message
CSVToDocument(row): content_column='{content_column}' not found in header for {source}. Available columns: {header} What it means
In row mode the component is strict: the content_column supplied to run() must appear in the CSV header, otherwise it cannot know which field holds the document text. The error lists the actual header columns found.
Solutions
- Set content_column to a name exactly matching a header field (case-sensitive).
- Inspect the 'Available columns' list in the message and pick the right one.
- Fix delimiter/quotechar so the header parses into the correct fields.
- Add or regenerate the header row in the CSV file.
Example fix
// before csv_conv.run(sources=[f], content_column="Body") // after (header is: id,text) csv_conv.run(sources=[f], content_column="text")
Defensive patterns
Strategy: validation
Validate before calling
import csv, io
def ensure_content_column(data: bytes, content_column: str, delimiter: str = ",") -> None:
header = next(csv.reader(io.StringIO(data.decode("utf-8")), delimiter=delimiter)) or []
if content_column not in header:
raise ValueError(f"content_column {content_column!r} not in header {header}") Try / catch
try:
result = conv.run(sources=[f], content_column=col)
except ValueError as e:
if "not found in header" in str(e):
col = col.lower() # retry with normalized case or pick a column you parse from the header
result = conv.run(sources=[f], content_column=col)
else:
raise Prevention
- Match header names exactly (case-sensitive); check for typos.
- Fix delimiter so the header parses into correct fields.
- Ensure CSV files include a header row.
- Normalize column names upstream before ingestion.
When it happens
Trigger: run(sources=[...], content_column='body') on a CSV whose header row lacks 'body' — due to typo, case mismatch, wrong delimiter mangling the header, or a missing header row.
Common situations: Renamed columns upstream; case-sensitive mismatch ('Text' vs 'text'); delimiter mismatch causing the whole first line to be one field; CSV without a header at all.
Related errors
- CSVToDocument: quotechar must be a single character.
- CSVToDocument(row): 'content_column' is required in run()…
- A file path must be provided in 'csv_file' parameter to…
- All lists in the JSON must have the same length
- CSVToDocument(row): could not parse CSV rows for
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/3255726936dadb15.
Report an issue: GitHub.
Appendix: source
Thrown at haystack/components/converters/csv.py:178
)
except Exception:
pass
# Create DictReader; if this fails, raise (no fallback)
try:
# ``restkey`` ensures surplus fields on ragged rows (rows with more values than the
# header, e.g. an unquoted comma inside a value) land under an explicit string key
# instead of the default ``None`` key, which would break ``Document`` id generation.
reader = csv.DictReader(
io.StringIO(data), delimiter=self.delimiter, quotechar=self.quotechar, restkey="extra_columns"
)
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:View on GitHub (pinned to e318778c9b)