HKUDS/DeepTutor · error · OpValidationError
edit: malformed target_id {op.target_id!r}
Error message
edit: malformed target_id {op.target_id!r} What it means
OpValidationError raised in _validate when an EditOp's target_id fails is_entry_id. Edits locate an existing entry by its entry id; target_id must be a well-formed entry id (the format produced when entries are created), otherwise the edit cannot be resolved and is rejected before any document mutation.
Source
Thrown at deeptutor/services/memory/ops.py:87
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):
raise OpValidationError(f"edit: malformed ref {ref!r}")
if op.target_id in deletes:
raise OpValidationError(
f"batch conflict: edit and delete on same id {op.target_id}"
)
edits.add(op.target_id)
elif isinstance(op, DeleteOp):
if not is_entry_id(op.target_id):View on GitHub (pinned to 3e82f13042)
Solutions
- Take target_id from doc entries themselves (e.g. via doc.entries / find results) rather than accepting it from free-form input
- Run is_entry_id(target_id) as a precondition check and reject early with a clear message to the caller/LLM
- Trim whitespace and re-fetch the entry list if ids may have been copy-pasted
Example fix
# before
op = EditOp(target_id=user_supplied_id, new_text=new_note, new_refs=[ref])
# after
from deeptutor.services.memory.ops import is_entry_id
if not is_entry_id(user_supplied_id):
raise ValueError("please pick an entry id from the list")
op = EditOp(target_id=user_supplied_id, new_text=new_note, new_refs=[ref]) Defensive patterns
Strategy: type-guard
Validate before calling
from deeptutor.services.memory.ops import is_entry_id
if not is_entry_id(target_id):
raise ValueError("target_id must be an entry id from doc.entries") Type guard
def is_editable_target(target_id: str) -> bool:
return is_entry_id(target_id) Try / catch
try:
ops.apply(doc, [op])
except OpValidationError as e:
if "malformed target_id" in str(e):
# re-prompt the LLM with the valid entry id list
raise RetryWithEntryList(e)
raise Prevention
- Source target_id from doc entries, never free-form input
- Expose only real entry ids in UIs/LLM tool schemas
- Strip and charset-check pasted ids
When it happens
Trigger: EditOp(target_id='some string', new_text=..., new_refs=[...]) where target_id isn't a valid entry id — e.g. passing an entry's text, a section name, a ref, or a truncated/copied id with whitespace.
Common situations: LLM edit tool-calls hallucinating or paraphrasing the id; ids round-tripped through JSON/logs and mangled; UI passing the display index instead of the entry id.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- add: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.tex
- add: invalid section {op.section!r}
- add: refs must be non-empty
- add: malformed ref {ref!r}
- edit: target_id {op.target_id} not found
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/a24f62df84f7bee4.
Report an issue: GitHub.