{"record":{"id":"555efbdda5388bcc","repo":"HKUDS/DeepTutor","slug":"record-not-found","errorCode":null,"errorMessage":"Record not found","messagePattern":"Record not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"deeptutor/api/routers/notebook.py","lineNumber":381,"sourceCode":"    )\n\n\n@router.delete(\"/{notebook_id}/records/{record_id}\")\nasync def remove_record(notebook_id: str, record_id: str):\n    \"\"\"\n    Remove record from notebook\n\n    Args:\n        notebook_id: Notebook ID\n        record_id: Record ID\n\n    Returns:\n        Deletion result\n    \"\"\"\n    try:\n        success = notebook_manager.remove_record(notebook_id, record_id)\n        if not success:\n            raise HTTPException(status_code=404, detail=\"Record not found\")\n        return {\"success\": True, \"message\": \"Record removed successfully\"}\n    except HTTPException:\n        raise\n    except NotebookCorruptedError as exc:\n        raise _unreadable(exc)\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@router.put(\"/{notebook_id}/records/{record_id}\")\nasync def update_record(notebook_id: str, record_id: str, request: UpdateRecordRequest):\n    \"\"\"Update an existing notebook record in place.\"\"\"\n    try:\n        # Forward only what the client actually sent. Passing every field\n        # unconditionally would hand `kb_name=None` to the service on every\n        # request and clear the record's knowledge-base link as a side effect\n        # of renaming it; the service's sentinel default only works if an\n        # omitted field never reaches it.","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/notebook.py#L363-L399","documentation":"404 raised when notebook_manager.remove_record returns falsy, meaning either the notebook or the record id passed on the path does not exist in the store. Deletion is only attempted after both ids resolve; otherwise the endpoint aborts with 'Record not found'.","triggerScenarios":"DELETE (or the remove_record route) with a record_id that was already deleted, a notebook_id that doesn't exist, or ids copied from a different environment/data directory.","commonSituations":"Double-submit of a delete button where the first request already removed the record; UI holding stale record ids after another client removed them; data directory reset between listing and deleting.","solutions":["Re-fetch the notebook's records to get current ids before deleting","Treat 404 on delete as idempotent success if the record is already gone","Confirm notebook_id is correct and the notebook still exists"],"exampleFix":"// before\nawait client.delete(f\"/notebook/{nb}/records/{rid}\")  # raises 404\n// after\nresp = await client.delete(f\"/notebook/{nb}/records/{rid}\")\nif resp.status_code == 404:\n    pass  # already removed; treat as success","handlingStrategy":"try-catch","validationCode":"resp = await client.get(f\"/notebook/{nb}/records\")\nexists = any(r[\"id\"] == rid for r in resp.json()[\"records\"])\nif not exists:\n    return  # already gone","typeGuard":null,"tryCatchPattern":"resp = await client.delete(f\"/notebook/{nb}/records/{rid}\")\nif resp.status_code == 404:\n    pass  # idempotent delete","preventionTips":["Treat delete 404 as success for idempotency","Disable delete buttons after first click to avoid double-submit","Refresh record lists before destructive actions"],"tags":["notebook","http-404","delete","fastapi"],"backgroundTag":"http-404-not-found","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}