unslothai/unsloth · warning · HTTPException
Invalid preset name
Error message
Invalid preset name
What it means
HTTP 422 raised directly by the DELETE /settings/generation-presets/{kind}/custom route (not pydantic) after it strips the query parameter name. It rejects empty names, the reserved name 'Default', and names longer than 80 characters — mirroring the create-side validator. A valid name that simply does not exist deletes nothing and still returns {'deleted': true}, so this 422 is purely about name shape.
Source
Thrown at studio/backend/routes/settings.py:456
return _upsert_custom_generation_preset("image", payload)
@router.put("/generation-presets/video/custom")
def upsert_custom_video_generation_preset(
payload: VideoGenerationPreset, current_subject: str = Depends(get_current_subject)
) -> dict[str, bool]:
return _upsert_custom_generation_preset("video", payload)
@router.delete("/generation-presets/{kind}/custom")
def delete_custom_generation_preset(
kind: Literal["image", "video"],
name: str,
current_subject: str = Depends(get_current_subject),
) -> dict[str, bool]:
name = name.strip()
if not name or name == "Default" or len(name) > 80:
raise HTTPException(status_code = 422, detail = "Invalid preset name")
delete_media_generation_preset(kind, name)
return {"deleted": True}
class UploadLimitPayload(BaseModel):
max_upload_size_mb: int = Field(..., ge = MIN_UPLOAD_LIMIT_MB, le = MAX_UPLOAD_LIMIT_MB)
class UploadLimitResponse(BaseModel):
max_upload_size_mb: int
max_upload_size_bytes: int
max_upload_size_label: str
default_upload_size_mb: int
min_upload_size_mb: int = MIN_UPLOAD_LIMIT_MB
max_allowed_upload_size_mb: int = MAX_UPLOAD_LIMIT_MB
class HuggingFaceTokenPayload(BaseModel):View on GitHub (pinned to 203007d190)
Solutions
- Send the exact stored custom preset name, trimmed, 1-80 chars, not 'Default'.
- Guard in the client: skip the DELETE when the row is the built-in default preset.
- If names mismatch, GET the preset list first and delete by the returned name.
Example fix
// before
await api.delete(`/settings/generation-presets/${kind}/custom?name=${raw}`); // raw = ' '
// after
const name = raw.trim();
if (name && name !== 'Default' && name.length <= 80) {
await api.delete(`/settings/generation-presets/${kind}/custom?name=${encodeURIComponent(name)}`);
} Defensive patterns
Strategy: validation
Validate before calling
function validDeleteName(raw: string): boolean {
const name = raw.trim();
return name.length >= 1 && name.length <= 80 && name !== 'Default';
}
if (validDeleteName(row.name)) {
await api.delete(`/settings/generation-presets/${kind}/custom?name=${encodeURIComponent(row.name.trim())}`);
} Type guard
function isDeletablePresetName(v: unknown): v is string {
return typeof v === 'string' && v.trim().length >= 1 && v.trim().length <= 80 && v.trim() !== 'Default';
} Try / catch
try { await api.delete(url); }
catch (e) {
if (e.status === 422) { skipRow(); return; } // name shape invalid — nothing to delete
throw e;
} Prevention
- Delete only rows that came from the preset list GET, by their exact stored name.
- Never offer delete for the built-in 'Default' row.
- encodeURIComponent the name to survive spaces.
When it happens
Trigger: DELETE with name="" or whitespace-only (URL-encoded %20), name=Default, or a name over 80 characters; often a frontend bug sending an untrimmed or empty string.
Common situations: Delete button clicked on a row whose name field is empty; sending the display label 'Default' instead of a real custom preset name; trailing whitespace introduced by copy-paste or URL encoding of spaces.
Related errors
- Preset name is reserved or empty
- str(exc)
- Invalid version.
- Provide either content_base64 or file_ids, not both
- Provide either content_base64 or file_ids
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/48f4e0f009e524f5.
Report an issue: GitHub.