HKUDS/DeepTutor · warning · HTTPException

Record or target notebook not found

Error message

Record or target notebook not found

What it means

404 from copy_record when notebook_manager.copy_record returns falsy: either the source record/notebook doesn't exist, or the target_notebook_id in the MoveRecordRequest body doesn't exist. The single message covers both cases.

Source

Thrown at deeptutor/api/routers/notebook.py:425

        )
        if not updated:
            raise HTTPException(status_code=404, detail="Record not found")
        return {"success": True, "record": updated}
    except HTTPException:
        raise
    except NotebookCorruptedError as exc:
        raise _unreadable(exc)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/{notebook_id}/records/{record_id}/copy")
async def copy_record(notebook_id: str, record_id: str, request: MoveRecordRequest):
    """Duplicate a record into another notebook under a fresh id."""
    try:
        copied = notebook_manager.copy_record(notebook_id, record_id, request.target_notebook_id)
        if not copied:
            raise HTTPException(status_code=404, detail="Record or target notebook not found")
        return {"success": True, "record": copied}
    except HTTPException:
        raise
    except NotebookCorruptedError as exc:
        raise _unreadable(exc)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/{notebook_id}/records/{record_id}/move")
async def move_record(notebook_id: str, record_id: str, request: MoveRecordRequest):
    """Move a record from this notebook into another one."""
    try:
        moved = notebook_manager.move_record(notebook_id, record_id, request.target_notebook_id)
        if not moved:
            raise HTTPException(status_code=404, detail="Record or target notebook not found")
        return {"success": True, "record": moved}
    except HTTPException:

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Verify both notebook ids exist via GET /notebooks before copying
  2. Refresh the source record list to confirm record_id is still present
  3. Create the target notebook first if it doesn't exist

Example fix

// before
await client.post(f"/notebook/{nb}/records/{rid}/copy", json={"target_notebook_id": "ghost"})
// after
await client.post("/notebook/create", json={"name": "Target"})
tid = (await client.get("/notebooks")).json()["notebooks"][-1]["id"]
await client.post(f"/notebook/{nb}/records/{rid}/copy", json={"target_notebook_id": tid})
Defensive patterns

Strategy: validation

Validate before calling

ids = {b["id"] for b in (await client.get("/notebooks")).json()["notebooks"]}
if request_target not in ids:
    await create_notebook(request_target)

Try / catch

resp = await client.post(copy_url, json=payload)
if resp.status_code == 404:
    await refresh_notebooks_and_records()

Prevention

When it happens

Trigger: POST /{notebook_id}/records/{record_id}/copy where record_id is stale/removed or request.target_notebook_id names a notebook that was never created or deleted.

Common situations: Target notebook dropdown in the UI holding stale options; copying right after the source record was moved/deleted by another session; typos in target notebook id.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/d7a2cd0a9558fb77. Report an issue: GitHub.