deepset-ai/haystack · error · TypeError

PythonCodeSplitter only works with text documents (str conte

Error message

PythonCodeSplitter only works with text documents (str content).

What it means

PythonCodeSplitter.run() raises TypeError when a document's content is not a str. The splitter tokenizes Python source and can only handle string content; arbitrary objects (bytes, lists, dicts) are rejected explicitly rather than failing obscurely later.

Source

Thrown at haystack/components/preprocessors/python_code_splitter.py:585

        Split each Python source ``Document`` into syntax-aware chunks.

        :param documents: Documents whose ``content`` is Python source code. Each
            document's ``meta`` is propagated onto its chunks.
        :returns: ``{"documents": [...]}`` where each chunk's meta additionally carries
            ``source_id``, ``split_id``, ``start_line``, ``end_line``, ``unit_kinds`` and
            - where applicable - ``include_classes``, ``decorators``, ``docstrings``,
            ``secondary_split``.
        :raises ValueError: If any document's content is ``None``.
        :raises TypeError: If any document's content is not a string.
        :raises SyntaxError: If a document's content is not valid Python.
        """
        for doc in documents:
            if doc.content is None:
                raise ValueError(
                    f"PythonCodeSplitter only works with text documents but content for document ID {doc.id} is None."
                )
            if not isinstance(doc.content, str):
                raise TypeError("PythonCodeSplitter only works with text documents (str content).")

        final_docs: list[Document] = []
        for doc in documents:
            assert doc.content is not None  # narrowed by the loop above
            if not doc.content.strip():
                logger.warning("Document ID {doc_id} has empty content. Skipping this document.", doc_id=doc.id)
                continue

            units = self._extract_units(doc.content)
            if not units:
                continue

            chunks = self._merge_units(units)
            split_id = 0
            for chunk in chunks:
                if len(chunk) == 1 and self._is_oversized(chunk[0]):
                    for piece in self._secondary_split(chunk[0], doc):
                        piece.meta["split_id"] = split_id

View on GitHub (pinned to e318778c9b)

Solutions

  1. Decode bytes before wrapping: Document(content=data.decode('utf-8')).
  2. Ensure upstream components emit str content (check the converter used).
  3. Add an isinstance check in a custom component before emitting documents.

Example fix

// before
Document(content=open(path, 'rb').read())
// after
Document(content=open(path, 'r', encoding='utf-8').read())
Defensive patterns

Strategy: type-guard

Validate before calling

bad = [d.id for d in documents if not isinstance(d.content, str)]
if bad:
    raise TypeError(f'Non-str content in documents: {bad}')

Type guard

def is_text_document(doc) -> bool:
    return isinstance(doc.content, str)

documents = [d for d in documents if is_text_document(d)]

Try / catch

try:
    result = splitter.run(documents=docs)
except TypeError as e:
    logger.error('Non-str document content: %s', e)
    result = splitter.run(documents=[d for d in docs if isinstance(d.content, str)])

Prevention

When it happens

Trigger: Passing documents whose content is bytes (e.g. raw file reads), a list of chunks, or any non-str object; constructing Document(content=<non-str>) manually and feeding it to run().

Common situations: Reading files in binary mode ('rb') upstream; custom components that store structured data in content; version changes after migrating from another splitter that accepted different types.

Related errors


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