HKUDS/DeepTutor · warning · HTTPException
No fields to update
Error message
No fields to update
What it means
400 raised when UpdateRecordRequest.model_dump(exclude_unset=True) yields no fields — the client sent a PUT body with no keys (or only fields explicitly unset). The endpoint deliberately requires at least one changed field because the service uses sentinel defaults for omitted fields.
Solutions
- Include at least one field you actually intend to change in the request body
- Skip the PUT call entirely when the client-side diff is empty
- Check the request model definition to confirm field names
Example fix
// before
await client.put(f"/notebook/{nb}/records/{rid}", json={})
// after
await client.put(f"/notebook/{nb}/records/{rid}", json={"title": "New title"}) Defensive patterns
Strategy: validation
Validate before calling
changes = {k: v for k, v in diff.items() if v is not None}
if not changes:
return # nothing to update, skip PUT Prevention
- Short-circuit empty diffs in the client before calling the API
- Send only fields that actually changed
When it happens
Trigger: PUT /{notebook_id}/records/{record_id} with an empty JSON object {} or a body where every field is unset.
Common situations: Frontend building the update payload from a diff that turns out empty; passing a pre-filled request model with exclude_unset semantics; schema change removing a field that the client still relies on to trigger updates.
Related errors
- Both name and agent_kind are required.
- Both name and server_url are required.
- Client ID and API key are required.
- {exc}
- Invalid folder path
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/cdfc63722170c2ee.
Report an issue: GitHub.
Appendix: source
Thrown at deeptutor/api/routers/notebook.py:402
raise
except NotebookCorruptedError as exc:
raise _unreadable(exc)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.put("/{notebook_id}/records/{record_id}")
async def update_record(notebook_id: str, record_id: str, request: UpdateRecordRequest):
"""Update an existing notebook record in place."""
try:
# Forward only what the client actually sent. Passing every field
# unconditionally would hand `kb_name=None` to the service on every
# request and clear the record's knowledge-base link as a side effect
# of renaming it; the service's sentinel default only works if an
# omitted field never reaches it.
changes = request.model_dump(exclude_unset=True)
if not changes:
raise HTTPException(status_code=400, detail="No fields to update")
updated = notebook_manager.update_record(
notebook_id=notebook_id,
record_id=record_id,
**changes,
)
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):View on GitHub (pinned to 3e82f13042)