deepset-ai/haystack · error · ValueError

CSVToDocument: delimiter must be a single character.

Error message

CSVToDocument: delimiter must be a single character.

What it means

CSVToDocument.__init__ validates that the delimiter is exactly one character, since Python's csv module requires single-character delimiters. Passing a multi-character string fails fast at construction.

Source

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

            If True, the full path of the file is stored in the metadata of the document.
            If False, only the file name is stored.
        :param conversion_mode:
            - "file" (default): one Document per CSV file whose content is the raw CSV text.
            - "row": convert each CSV row to its own Document (requires `content_column` in `run()`).
        :param delimiter:
            CSV delimiter used when parsing in row mode (passed to ``csv.DictReader``).
        :param quotechar:
            CSV quote character used when parsing in row mode (passed to ``csv.DictReader``).
        """
        self.encoding = encoding
        self.store_full_path = store_full_path
        self.conversion_mode = conversion_mode
        self.delimiter = delimiter
        self.quotechar = quotechar

        # Basic validation
        if len(self.delimiter) != 1:
            raise ValueError("CSVToDocument: delimiter must be a single character.")
        if len(self.quotechar) != 1:
            raise ValueError("CSVToDocument: quotechar must be a single character.")

    @component.output_types(documents=list[Document])
    def run(
        self,
        sources: list[str | Path | ByteStream],
        *,
        content_column: str | None = None,
        meta: dict[str, Any] | list[dict[str, Any]] | None = None,
    ) -> dict[str, Any]:
        """
        Converts CSV files to a Document (file mode) or to one Document per row (row mode).

        :param sources:
            List of file paths or ByteStream objects.
        :param content_column:
            **Required when** ``conversion_mode="row"``.

View on GitHub (pinned to e318778c9b)

Solutions

  1. Pass a single character, e.g. delimiter=';', ',', or '\t'.
  2. Pre-process multi-character-delimited files into a single-char-delimited CSV before conversion.
  3. Strip whitespace from user/config-supplied delimiter values before constructing the converter.

Example fix

// before
CSVToDocument(delimiter='||')
// after
import csv  # or preprocess the file
converter = CSVToDocument(delimiter=';')
Defensive patterns

Strategy: validation

Validate before calling

assert len(delimiter) == 1, f"delimiter must be a single character, got {delimiter!r}"
CSVToDocument(delimiter=delimiter)

Type guard

def is_single_char(s: str) -> bool:
    return isinstance(s, str) and len(s) == 1

Try / catch

try:
    converter = CSVToDocument(delimiter=delimiter)
except ValueError as e:
    if 'single character' in str(e):
        converter = CSVToDocument(delimiter=delimiter.strip()[0])
    else:
        raise

Prevention

When it happens

Trigger: CSVToDocument(delimiter='; ') or CSVToDocument(delimiter='\t ' where the source used a multi-char separator like '||' or a tab with trailing spaces).

Common situations: Copy-pasting separators from files that use multi-character delimiters; confusing tab ('\t') with the literal string 'tab'; configurable delimiter sourced from YAML/CLI containing whitespace.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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