HKUDS/DeepTutor · error · OpValidationError
add: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.tex
Error message
add: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.text)}) What it means
OpValidationError from ops.apply's _validate: an AddOp's text must be non-empty and at most _MAX_TEXT_LEN characters. AddOp appends a new memory entry, and oversized/empty text would break the document format and L2 budgets, so it is rejected up front before any mutation occurs (validation is atomic — no partial apply).
Source
Thrown at deeptutor/services/memory/ops.py:75
@dataclass
class ApplyReport:
accepted: bool
results: list[OpResult] = field(default_factory=list)
reason: str = ""
class OpValidationError(Exception):
"""Raised when a batch fails pre-flight validation."""
def _validate(doc: Document, ops: list[Op]) -> None:
edits: set[str] = set()
deletes: set[str] = set()
for op in ops:
if isinstance(op, AddOp):
if not op.text or len(op.text) > _MAX_TEXT_LEN:
raise OpValidationError(
f"add: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.text)})"
)
if not op.section or len(op.section) > _MAX_SECTION_LEN:
raise OpValidationError(f"add: invalid section {op.section!r}")
if not op.refs:
raise OpValidationError("add: refs must be non-empty")
for ref in op.refs:
if not is_valid_ref(ref):
raise OpValidationError(f"add: malformed ref {ref!r}")
elif isinstance(op, EditOp):
if not is_entry_id(op.target_id):
raise OpValidationError(f"edit: malformed target_id {op.target_id!r}")
if doc.find(op.target_id) is None:
raise OpValidationError(f"edit: target_id {op.target_id} not found")
if not op.new_text or len(op.new_text) > _MAX_TEXT_LEN:
raise OpValidationError(
f"edit: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.new_text)})"
)View on GitHub (pinned to 3e82f13042)
Solutions
- Clamp or reject the text before building the op: if not text or len(text) > _MAX_TEXT_LEN, skip/split the write
- Split very long content into multiple AddOps (each within the limit) or summarize it down
- Import _MAX_TEXT_LEN from deeptutor.services.memory.ops and validate against the library's own constant instead of hardcoding
Example fix
# before
op = AddOp(text=long_note, section="facts", refs=[ref])
result = ops.apply(doc, [op])
# after
from deeptutor.services.memory.ops import _MAX_TEXT_LEN
if long_note and len(long_note) <= _MAX_TEXT_LEN:
op = AddOp(text=long_note, section="facts", refs=[ref])
result = ops.apply(doc, [op]) Defensive patterns
Strategy: validation
Validate before calling
from deeptutor.services.memory.ops import _MAX_TEXT_LEN, OpValidationError assert isinstance(text, str) and 1 <= len(text) <= _MAX_TEXT_LEN
Type guard
def is_valid_add_text(text: str) -> bool:
return bool(text) and len(text) <= _MAX_TEXT_LEN Try / catch
try:
result = ops.apply(doc, ops_list)
except OpValidationError as e:
if e.args[0].startswith("add: text length"):
text = text[:_MAX_TEXT_LEN]
ops_list = rebuild(ops_list, text=text)
result = ops.apply(doc, ops_list)
else:
raise Prevention
- Clamp LLM-generated text before building AddOp
- Import length constants from ops.py rather than duplicating them
- Validate the whole op batch before applying since apply is atomic
When it happens
Trigger: Constructing AddOp(text='', section=..., refs=[...]) or AddOp with text longer than _MAX_TEXT_LEN (typically an LLM generating a bloated or empty memory note) and passing it to ops.apply(doc, [op]).
Common situations: LLM-generated memory writes without length clamping; truncating user input to the wrong bound; unit tests exercising validation boundaries; copying constants from another module with a different _MAX_TEXT_LEN.
Related errors
- edit: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.ne
- add: invalid section {op.section!r}
- add: refs must be non-empty
- add: malformed ref {ref!r}
- edit: malformed target_id {op.target_id!r}
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/6a415d252fa1348f.
Report an issue: GitHub.