invoke-ai/InvokeAI · error · HTTPException
Invalid preset data
Error message
Invalid preset data
What it means
update_style_preset (PATCH style preset) parses the multipart 'data' form field as JSON and validates it against the StylePresetFormData pydantic model. If the string is not valid JSON or the parsed object fails schema validation (missing/extra/ill-typed fields), the endpoint returns HTTP 400 with detail 'Invalid preset data'. It is a request-body contract error, not a server fault.
Source
Thrown at invokeai/app/api/routers/style_presets.py:120
image: Optional[UploadFile] = File(description="The image file to upload", default=None),
style_preset_id: str = Path(description="The id of the style preset to update"),
data: str = Form(description="The data of the style preset to update"),
) -> StylePresetRecordWithImage:
"""Updates a style preset"""
# Validate the data payload BEFORE any image-state mutation so a malformed
# request can't leave the preset image partially updated.
try:
parsed_data = json.loads(data)
validated_data = StylePresetFormData(**parsed_data)
name = validated_data.name
type = validated_data.type
positive_prompt = validated_data.positive_prompt
negative_prompt = validated_data.negative_prompt
is_public = validated_data.is_public
except (json.JSONDecodeError, pydantic.ValidationError):
raise HTTPException(status_code=400, detail="Invalid preset data")
record = await asyncio.to_thread(_load_record_or_404, style_preset_id)
_assert_preset_write(record, current_user)
if image is not None:
if not image.content_type or not image.content_type.startswith("image"):
raise HTTPException(status_code=415, detail="Not an image")
contents = await image.read()
try:
pil_image = await asyncio.to_thread(Image.open, io.BytesIO(contents))
except Exception:
ApiDependencies.invoker.services.logger.error(traceback.format_exc())
raise HTTPException(status_code=415, detail="Failed to read image")
try:
await asyncio.to_thread(View on GitHub (pinned to 0b6a024f2f)
Solutions
- Print/log the exact 'data' string sent and run json.loads on it client-side to confirm it is valid JSON.
- Validate the payload against StylePresetFormData (name, type, positive_prompt, negative_prompt, is_public) with the same pydantic model or the generated OpenAPI client type before sending.
- Ensure the field is sent as a single multipart form part named 'data' containing a JSON string, not as separate form fields.
- Regenerate the API client from the server's OpenAPI schema so the form schema matches the running server version.
Example fix
// before
curl -X PATCH .../style_presets/i/abc -F name="My preset" -F type="user"
// after
curl -X PATCH .../style_presets/i/abc \
-F 'data={"name":"My preset","type":"user","positive_prompt":"...","negative_prompt":"...","is_public":false}' Defensive patterns
Strategy: validation
Validate before calling
import json
def validate_preset_payload(data_str: str) -> dict:
payload = json.loads(data_str) # raises JSONDecodeError -> would be 400
required = {"name": str, "type": str, "positive_prompt": str, "negative_prompt": str, "is_public": bool}
for key, typ in required.items():
assert key in payload and isinstance(payload[key], typ), f"bad field: {key}"
return payload
validate_preset_payload(data_field) # run before PATCH/POST Type guard
def is_valid_preset_data(v: object) -> TypeGuard[dict]:
return (
isinstance(v, dict)
and isinstance(v.get("name"), str)
and isinstance(v.get("type"), str)
and isinstance(v.get("positive_prompt"), str)
and isinstance(v.get("negative_prompt"), str)
and isinstance(v.get("is_public"), bool)
) Try / catch
try {
await api.updateStylePreset({ stylePresetId, data: JSON.stringify(preset), image });
} catch (e) {
if (e.status === 400 && e.detail === "Invalid preset data") {
console.error("Payload failed schema:", JSON.stringify(preset));
} else throw e;
} Prevention
- Always JSON.stringify the preset object into the single 'data' form field.
- Use the generated OpenAPI client instead of hand-built form bodies.
- Validate against StylePresetFormData fields locally before every send.
- Round-trip test: json.loads(JSON.stringify(preset)) must succeed before upload.
When it happens
Trigger: PATCH /style_presets/i/{id} with multipart form where: data is not parseable JSON (truncated, single quotes, HTML error page), data omits a required StylePresetFormData field (name, type, positive_prompt, negative_prompt, is_public), or a field has the wrong type (e.g. is_public as string 'true' instead of boolean, unknown preset type enum value).
Common situations: Client builds the data field with JSON.stringify omitted (sends '[object Object]' or a Python dict repr); content-type confusion causing double-encoded JSON strings; SDK version drift where StylePresetFormData gained or renamed fields; hand-written curl tests sending raw key=value instead of JSON.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Administrator account already configured
- Failed to update video
- No external provider config fields provided
- str(e)
- The system user cannot be deleted, deactivated, promoted to
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/9a31315d56b570da.
Report an issue: GitHub.