fix(rag): reject invalid chunk_size/chunk_overlap in RecursiveCharacterTextSplitter

Fixes #38980
This commit is contained in:
Sanjay Santhanam 2026-10-11 13:58:05 -07:00
parent c0ca4a51f7
commit 3eaab28be5
3 changed files with 68 additions and 0 deletions

View file

@ -23,6 +23,15 @@ class RecursiveCharacterTextSplitter:
chunk_overlap: int = DEFAULT_CHUNK_OVERLAP,
separators: list[str] | None = None,
):
if chunk_size <= 0:
raise ValueError(f"chunk_size must be positive, got {chunk_size}")
if chunk_overlap < 0:
raise ValueError(f"chunk_overlap must be non-negative, got {chunk_overlap}")
if chunk_overlap >= chunk_size:
raise ValueError(
"chunk_overlap must be smaller than chunk_size, "
f"got chunk_overlap={chunk_overlap}, chunk_size={chunk_size}"
)
self.chunk_size = chunk_size
self.chunk_overlap = chunk_overlap
self.separators = separators or ["\n\n", "\n", " ", ""]

View file

@ -0,0 +1,59 @@
from typing import Final
import pytest
from litellm.constants import DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE
from litellm.rag.text_splitters.recursive_character_text_splitter import (
RecursiveCharacterTextSplitter,
)
@pytest.mark.parametrize(
"chunk_size,chunk_overlap",
[
(100, 100),
(100, 150),
(1, 1),
],
)
def test_chunk_overlap_at_least_chunk_size_is_rejected(
chunk_size: int, chunk_overlap: int
) -> None:
with pytest.raises(
ValueError, match="chunk_overlap must be smaller than chunk_size"
):
RecursiveCharacterTextSplitter(
chunk_size=chunk_size, chunk_overlap=chunk_overlap
)
@pytest.mark.parametrize("chunk_size", [0, -1, -100])
def test_non_positive_chunk_size_is_rejected(chunk_size: int) -> None:
with pytest.raises(ValueError, match="chunk_size must be positive"):
RecursiveCharacterTextSplitter(chunk_size=chunk_size)
@pytest.mark.parametrize("chunk_overlap", [-1, -100])
def test_negative_chunk_overlap_is_rejected(chunk_overlap: int) -> None:
with pytest.raises(ValueError, match="chunk_overlap must be non-negative"):
RecursiveCharacterTextSplitter(chunk_overlap=chunk_overlap)
def test_force_split_path_terminates_with_valid_overlap() -> None:
splitter: Final = RecursiveCharacterTextSplitter(
chunk_size=10, chunk_overlap=2, separators=["\n\n"]
)
chunks: Final = splitter.split_text("abcdefghijklmnop")
assert chunks == ["abcdefghij", "ijklmnop"]
def test_valid_overlap_keeps_splitting() -> None:
splitter: Final = RecursiveCharacterTextSplitter(chunk_size=10, chunk_overlap=2)
chunks: Final = splitter.split_text("abcdefghijklmnop")
assert chunks == ["abcdefghij", "ijklmnop"]
def test_defaults_construct_without_error() -> None:
splitter: Final = RecursiveCharacterTextSplitter()
assert splitter.chunk_size == DEFAULT_CHUNK_SIZE
assert splitter.chunk_overlap == DEFAULT_CHUNK_OVERLAP