Sume 400 invalid_request: read details.errors[].path to find the field
A Sume 400 invalid_request lists each bad field in details.errors with path, loc, message and type. Read them in Python instead of guessing from the message.

When a Sume request fails schema validation you get HTTP 400 with error.code set to invalid_request, the message Invalid request body, parameters, or headers., and the real answer in error.details.errors: one object per failing field, each with path, loc, message and type. Read path and you know which field to fix before you resend anything.
What does the 400 body contain?
The API code that builds this response turns each validator issue into four keys. path is the field as a dotted string, loc is the same path as an array, message is the validator's sentence, and type is the validator keyword such as required, enum or type. For a missing required property the property name is appended to the path, so a body with no prompt reports prompt. The envelope around it is the normal one: request_id, category: validation, retryable: false and next_action: fix_input.
One wrinkle: the example on the docs errors page shows details as a list. The API code builds an object with an errors array, and its own tests assert details.errors[0].path on asset registration and on a trending-videos search. Parse both shapes defensively and you will survive either.
How do I print the failing fields?
This function takes the parsed JSON of any Sume error and returns readable lines. It also runs on an empty or non-validation body.
def field_errors(body: dict) -> list[str]:
err = body.get("error") or {}
details = err.get("details")
if isinstance(details, dict):
items = details.get("errors") or []
elif isinstance(details, list):
items = details
else:
items = []
lines = []
for item in items:
if not isinstance(item, dict):
continue
path = item.get("path") or ".".join(map(str, item.get("loc", [])))
lines.append(f"{path or '(body)'}: {item.get('message', 'invalid')} [{item.get('type', '?')}]")
if not lines:
lines.append(f"{err.get('code', 'unknown')}: {err.get('message', '')}")
return lines
sample = {"error": {"code": "invalid_request", "details": {"errors": [
{"path": "prompt", "loc": ["prompt"], "message": "must have required property 'prompt'", "type": "required"}]}}}
print("\n".join(field_errors(sample)))Which 400s are not this one?
Some 400s are named. A model id that is not in the catalog on the image, TTS Router and Music Router routes returns model_not_found with a catalog_url; a bad Timeline transition.type, fit or output.fps returns invalid_transition_type, invalid_fit or invalid_fps with the allowed values; a Video filter program returns codes such as unsupported_filter_op. A body sent without a JSON content type is a 415, not a 400. Check error.code first and fall back to details.errors only for invalid_request.
| error.code | Status | Where the fix is |
|---|---|---|
invalid_request | 400 | details.errors[].path and message |
model_not_found | 400 or 404 by route | details.catalog_url lists accepted ids |
invalid_transition_type, invalid_fit, invalid_fps | 400 | details.allowed and details.field |
unsupported_media_type | 415 | details.received_content_type; send application/json |
payload_too_large | 413 | details.limit_bytes; shrink the body |
Should I retry after a 400?
No. retryable is false and nothing was started, so resending the same body returns the same 400. Fix the named field, then send the corrected request. If the response also carries a request_id and status_url in details, a job row already exists; see the related post on a 400 that returns a job id.
Sources
Related posts
More in Developers
- A Sume 400 that returns a job id: input rejected at provider submit
Most Sume 400s create nothing, but a provider input rejected at submit leaves a failed job, a request_id and a refund. How to read it and what key to use.
- Sume 404 resource_not_found: job_not_found and model_not_found overlap
Every Sume 404 reports public_reason resource_not_found, whatever the code. Branch on error.code to tell a missing job from a bad model id or a missing asset.
- Sume 409 job_not_queued: the job left the queue before it started
What the Sume 409 job_not_queued means: a submit found its job no longer queued, sent nothing to the provider, and the error is not retryable by resending.
- Sume generation_capacity_exhausted: the 503, job reason and flag
Sume reports provider capacity three ways: HTTP 503 provider_capacity_exceeded, a job reason generation_capacity_exhausted, and a sync flag. All three retry.
Written by Sume