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.

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)

Solutions

  1. Include at least one field you actually intend to change in the request body
  2. Skip the PUT call entirely when the client-side diff is empty
  3. 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

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


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