HKUDS/DeepTutor · error · OpValidationError
add: invalid section {op.section!r}
Error message
add: invalid section {op.section!r} What it means
OpValidationError raised in _validate when an AddOp's section is empty or exceeds _MAX_SECTION_LEN. The section names the heading/bucket the new entry is filed under in the memory document; blank or oversized section strings would corrupt the document structure, so they are rejected before any write.
Source
Thrown at deeptutor/services/memory/ops.py:79
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)})"
)
if not op.new_refs:
raise OpValidationError("edit: refs must be non-empty")
for ref in op.new_refs:
if not is_valid_ref(ref):View on GitHub (pinned to 3e82f13042)
Solutions
- Normalize the section to a fixed short vocabulary (e.g. strip, lowercase, map to known sections) before constructing AddOp
- Enforce a client-side maxlength equal to _MAX_SECTION_LEN (import it from ops.py to stay in sync)
- Reject/fallback to a default section like 'notes' when validation fails
Example fix
# before op = AddOp(text=note, section=llm_section, refs=[ref]) # after section = (llm_section or "notes").strip()[:_MAX_SECTION_LEN] or "notes" op = AddOp(text=note, section=section, refs=[ref])
Defensive patterns
Strategy: validation
Validate before calling
from deeptutor.services.memory.ops import _MAX_SECTION_LEN
section = (raw_section or "").strip()
if not (1 <= len(section) <= _MAX_SECTION_LEN):
section = "notes" Type guard
def is_valid_section(section: str) -> bool:
return bool(section) and len(section) <= _MAX_SECTION_LEN Try / catch
try:
ops.apply(doc, [op])
except OpValidationError as e:
if "invalid section" in str(e):
op = replace(op, section="notes")
ops.apply(doc, [op])
else:
raise Prevention
- Constrain LLM section output to a fixed short vocabulary
- Set maxlength on any UI field feeding section
- Map/normalize sections at the boundary of your system
When it happens
Trigger: AddOp(text=..., section='' or a section string longer than _MAX_SECTION_LEN, refs=[...]) passed to ops.apply. Commonly an LLM hallucinating a verbose 'section' like a full sentence instead of a short label, or a default/None coerced to ''.
Common situations: Free-form LLM output used directly as section; UI text input without maxlength feeding section; renaming sections programmatically with generated strings; locale variants making labels longer than expected.
Related errors
- add: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.tex
- add: refs must be non-empty
- add: malformed ref {ref!r}
- edit: malformed target_id {op.target_id!r}
- edit: target_id {op.target_id} not found
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/0337104e2a6dab1a.
Report an issue: GitHub.