{"record":{"id":"429ad511946bbb7b","repo":"unslothai/unsloth","slug":"no-fields-to-update-429ad5","errorCode":null,"errorMessage":"No fields to update","messagePattern":"No fields to update","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"studio/backend/routes/providers.py","lineNumber":356,"sourceCode":"            if metadata_requested:\n                try:\n                    providers_db.update_provider(\n                        id = provider_id,\n                        display_name = existing[\"display_name\"],\n                        base_url = existing[\"base_url\"],\n                        is_enabled = bool(existing[\"is_enabled\"]),\n                        models = existing.get(\"models\") or [],\n                        available_models = existing.get(\"available_models\") or [],\n                        max_output_tokens = existing.get(\"max_output_tokens\"),\n                    )\n                except Exception:\n                    logger.exception(\n                        \"provider.update_metadata_rollback_failed\", provider_id = provider_id\n                    )\n            raise\n\n    if not metadata_requested and not payload.encrypted_api_key and not payload.clear_api_key:\n        raise HTTPException(status_code = 400, detail = \"No fields to update\")\n\n    row = providers_db.get_provider(provider_id)\n    return _provider_response(row)\n\n\n@router.put(\"/{provider_id}/api-key/migrate\", response_model = ProviderResponse)\nasync def migrate_provider_api_key(\n    provider_id: str,\n    payload: ProviderCredentialMigration,\n    credential: tuple = Depends(get_current_credential),\n    via_api_key: bool = Depends(authenticated_via_api_key),\n):\n    \"\"\"Insert a browser legacy key only when this provider has no saved key.\"\"\"\n    require_ui_session(via_api_key)\n    if providers_db.get_provider(provider_id) is None:\n        raise HTTPException(status_code = 404, detail = \"Provider not found\")\n    api_key = resolve_provider_api_key_or_400(\n        None, payload.encrypted_api_key, allow_saved_key = False","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/providers.py#L338-L374","documentation":"A 400 from PUT /api/providers/{provider_id}: the payload contained none of the updatable fields — no metadata fields (display_name, base_url, is_enabled, models, available_models, max_output_tokens), no encrypted_api_key, and no clear_api_key. The endpoint refuses no-op updates so callers notice malformed payloads instead of silently succeeding.","triggerScenarios":"PUT with an empty JSON body {}; a client that builds the diff body conditionally and ends up with zero keys; serialization bugs dropping all fields before send.","commonSituations":"Diff-based update code where nothing changed; DTO field names not matching the API schema (silently ignored); a 'save' button firing with an untouched form represented as {}.","solutions":["Include at least one field you intend to change, e.g. display_name.","In diff-based clients, skip the PUT when the computed change set is empty.","Verify field names against ProviderUpdate — unknown keys are ignored and can leave the body effectively empty."],"exampleFix":"// before\nconst body = diff(left, right); // {} when nothing changed\nawait putProvider(id, body);\n// after\nconst body = diff(left, right);\nif (Object.keys(body).length === 0) return; // nothing to save\nawait putProvider(id, body);","handlingStrategy":"validation","validationCode":"const UPDATABLE = [\"display_name\", \"base_url\", \"is_enabled\", \"models\", \"available_models\", \"max_output_tokens\", \"encrypted_api_key\", \"clear_api_key\"];\nconst hasUpdate = UPDATABLE.some(f => f in body);\nif (!hasUpdate) throw new Error(\"PUT body contains no updatable fields\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Skip the PUT when your computed diff is empty.","Verify field names against ProviderUpdate; unknown fields are ignored and can leave the payload effectively empty."],"tags":["validation","no-op","providers"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}