{"record":{"id":"a24f62df84f7bee4","repo":"HKUDS/DeepTutor","slug":"edit-malformed-target-id-op-target-id-r","errorCode":null,"errorMessage":"edit: malformed target_id {op.target_id!r}","messagePattern":"edit: malformed target_id (.+?)","errorType":"validation","errorClass":"OpValidationError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/memory/ops.py","lineNumber":87,"sourceCode":"    edits: set[str] = set()\n    deletes: set[str] = set()\n\n    for op in ops:\n        if isinstance(op, AddOp):\n            if not op.text or len(op.text) > _MAX_TEXT_LEN:\n                raise OpValidationError(\n                    f\"add: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.text)})\"\n                )\n            if not op.section or len(op.section) > _MAX_SECTION_LEN:\n                raise OpValidationError(f\"add: invalid section {op.section!r}\")\n            if not op.refs:\n                raise OpValidationError(\"add: refs must be non-empty\")\n            for ref in op.refs:\n                if not is_valid_ref(ref):\n                    raise OpValidationError(f\"add: malformed ref {ref!r}\")\n        elif isinstance(op, EditOp):\n            if not is_entry_id(op.target_id):\n                raise OpValidationError(f\"edit: malformed target_id {op.target_id!r}\")\n            if doc.find(op.target_id) is None:\n                raise OpValidationError(f\"edit: target_id {op.target_id} not found\")\n            if not op.new_text or len(op.new_text) > _MAX_TEXT_LEN:\n                raise OpValidationError(\n                    f\"edit: text length must be 1..{_MAX_TEXT_LEN} (got {len(op.new_text)})\"\n                )\n            if not op.new_refs:\n                raise OpValidationError(\"edit: refs must be non-empty\")\n            for ref in op.new_refs:\n                if not is_valid_ref(ref):\n                    raise OpValidationError(f\"edit: malformed ref {ref!r}\")\n            if op.target_id in deletes:\n                raise OpValidationError(\n                    f\"batch conflict: edit and delete on same id {op.target_id}\"\n                )\n            edits.add(op.target_id)\n        elif isinstance(op, DeleteOp):\n            if not is_entry_id(op.target_id):","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/memory/ops.py#L69-L105","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nop = EditOp(target_id=user_supplied_id, new_text=new_note, new_refs=[ref])\n\n# after\nfrom deeptutor.services.memory.ops import is_entry_id\nif not is_entry_id(user_supplied_id):\n    raise ValueError(\"please pick an entry id from the list\")\nop = EditOp(target_id=user_supplied_id, new_text=new_note, new_refs=[ref])","handlingStrategy":"type-guard","validationCode":"from deeptutor.services.memory.ops import is_entry_id\nif not is_entry_id(target_id):\n    raise ValueError(\"target_id must be an entry id from doc.entries\")","typeGuard":"def is_editable_target(target_id: str) -> bool:\n    return is_entry_id(target_id)","tryCatchPattern":"try:\n    ops.apply(doc, [op])\nexcept OpValidationError as e:\n    if \"malformed target_id\" in str(e):\n        # re-prompt the LLM with the valid entry id list\n        raise RetryWithEntryList(e)\n    raise","preventionTips":["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"],"tags":["validation","memory","ops","entry-id"],"backgroundTag":"payload-validation-failed","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}