{"record":{"id":"5695720e262f6112","repo":"HKUDS/DeepTutor","slug":"no-records-provided","errorCode":null,"errorMessage":"No records provided","messagePattern":"No records provided","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deeptutor/api/routers/mastery_path.py","lineNumber":390,"sourceCode":"\n\nclass NotebookRecordInput(BaseModel):\n    id: str\n    type: str = \"note\"\n    title: str = \"\"\n    output: str = \"\"\n\n\nclass GenerateFromNotebookRequest(BaseModel):\n    notebook_id: str\n    records: list[NotebookRecordInput]\n\n\n@router.post(\"/progress/{book_id}/generate-from-notebook\")\nasync def generate_from_notebook(book_id: str, body: GenerateFromNotebookRequest):\n    _validate_book_id(book_id)\n    if not body.records:\n        raise HTTPException(status_code=400, detail=\"No records provided\")\n\n    records_data = [\n        {\n            \"type\": html.escape(r.type[:50], quote=False),\n            \"title\": html.escape(r.title[:200], quote=False),\n            \"output\": html.escape(r.output[:500], quote=False),\n        }\n        for r in body.records[:20]\n    ]\n    records_json = json.dumps(records_data, ensure_ascii=False)\n    from deeptutor.services.llm import complete\n\n    language = get_response_language()\n    system_prompt, prompt = learning_prompts.notebook_generation_prompts(language, records_json)\n    response = await complete(prompt=prompt, system_prompt=system_prompt)\n    # LLMs commonly fence/slightly-malform JSON; use the shared fence-stripping\n    # repair parser instead of bare json.loads so the common case isn't a 502.\n    data = parse_json_response(response, fallback=None)","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/mastery_path.py#L372-L408","documentation":"Raised by the POST /progress/{book_id}/generate-from-notebook endpoint when the request body contains no records. The endpoint converts notebook records into a generated learning plan, so an empty records list means there is nothing to generate from, and the server rejects it with a 400 before calling the LLM.","triggerScenarios":"POST /progress/{book_id}/generate-from-notebook with a GenerateFromNotebookRequest whose records array is empty ([]) or omitted entirely (defaults to empty).","commonSituations":"Frontend submits the form before the user has created any notebook entries; the notebook feature being tested against a fresh account with no records; a client-side bug filtering out all records before submission.","solutions":["Ensure the client collects at least one notebook record before submitting the request","Check client-side state: verify the records array is populated (e.g. notebook entries exist for the current book)","Add a UI guard/disable on the submit button when the notebook is empty","If records are being transformed client-side, log the payload before sending to confirm they survive filtering"],"exampleFix":"// before\nawait fetch(`/progress/${bookId}/generate-from-notebook`, {\n  method: \"POST\",\n  body: JSON.stringify({ records: notebookRecords }), // notebookRecords is []\n});\n\n// after\nif (notebookRecords.length === 0) {\n  alert(\"Add at least one notebook record first\");\n  return;\n}\nawait fetch(`/progress/${bookId}/generate-from-notebook`, {\n  method: \"POST\",\n  body: JSON.stringify({ records: notebookRecords }),\n});","handlingStrategy":"validation","validationCode":"if (!records || records.length === 0) {\n  throw new Error('Cannot generate from notebook: no records');\n}\nawait api.post(`/progress/${bookId}/generate-from-notebook`, { records });","typeGuard":"function hasRecords(req: GenerateFromNotebookRequest): boolean {\n  return Array.isArray(req.records) && req.records.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Disable the generate button until at least one notebook record exists","Validate records.length > 0 client-side before the POST","Show the record count in the UI so an empty notebook is obvious"],"tags":["api","validation","notebook","bad-request"],"backgroundTag":"empty-request-body","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}