deepset-ai/haystack · error · ValueError
All separators must be strings.
Error message
All separators must be strings.
What it means
RecursiveSplitter accepts a 'separators' list used to recursively split text; every entry must be a str. Non-string entries (None, ints, regex objects, lists) cannot be used as string separators, so _check_params rejects the list at construction.
Source
Thrown at haystack/components/preprocessors/recursive_splitter.py:121
"""
if self._is_warmed_up:
return
if "sentence" in self.separators:
self.nltk_tokenizer = self._get_custom_sentence_tokenizer(self.sentence_splitter_params)
if self.split_units == "token":
tiktoken_imports.check()
self.tiktoken_tokenizer = tiktoken.get_encoding("o200k_base")
self._is_warmed_up = True
def _check_params(self) -> None:
if self.split_length < 1:
raise ValueError("Split length must be at least 1 character.")
if self.split_overlap < 0:
raise ValueError("split_overlap must be greater than or equal to 0.")
if self.split_overlap >= self.split_length:
raise ValueError("Overlap cannot be greater than or equal to the chunk size.")
if not all(isinstance(separator, str) for separator in self.separators):
raise ValueError("All separators must be strings.")
@staticmethod
def _get_custom_sentence_tokenizer(sentence_splitter_params: dict[str, Any]) -> Any:
from haystack.components.preprocessors.sentence_tokenizer import SentenceSplitter
return SentenceSplitter(**sentence_splitter_params)
def _split_chunk(self, current_chunk: str) -> tuple[str, str]:
"""
Splits a chunk based on the split_length and split_units attribute.
:param current_chunk: The current chunk to be split.
:returns:
A tuple containing the current chunk and the remaining chunk.
"""
if self.split_units == "word":
words = current_chunk.split()
current_chunk = " ".join(words[: self.split_length])View on GitHub (pinned to e318778c9b)
Solutions
- Pass a list of plain strings: separators=['\n\n', '\n', '.', ' '].
- Validate/coerce config values: separators=[str(s) for s in raw_separators if s is not None].
- If only defaults are wanted, omit the separators parameter.
Example fix
// before splitter = RecursiveSplitter(separators=['\n\n', None, 3]) // after splitter = RecursiveSplitter(separators=['\n\n', '\n', '. '])
Defensive patterns
Strategy: validation
Validate before calling
if not all(isinstance(s, str) for s in separators):
raise TypeError('All separators must be strings') Type guard
def all_str_separators(seps) -> bool:
return isinstance(seps, list) and all(isinstance(s, str) for s in seps) Try / catch
try:
splitter = RecursiveSplitter(separators=seps)
except ValueError as e:
logger.error('Invalid separators: %s', e)
splitter = RecursiveSplitter() # default separators Prevention
- Quote separator strings in YAML so '\n' is not mangled and values stay strings.
- Filter None entries after deserializing JSON configs: [s for s in raw if isinstance(s, str)].
- Keep a shared constants module of separator lists instead of inline literals.
When it happens
Trigger: RecursiveSplitter(separators=['\n\n', None]), passing a single string instead of a list of strings mixed with non-str items, or serializing/deserializing configs where a separator became null.
Common situations: Pipeline YAML where a separator value is unquoted and parsed as a number/bool/null; JSON configs with null entries; building separators programmatically from mixed sources.
Understand the failure class
Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.
Related errors
- header_split_levels must be a non-empty list.
- min_effective_lines must be at least 1.
- max_effective_lines must be at least 1.
- expected_chars_per_line must be at least 1.
- oversized_factor must be at least 1.
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/e1e05f877714a5ac.
Report an issue: GitHub.