Attachment Errors
| Status | Where | Meaning | How to handle |
|---|---|---|---|
400 URL not allowed | POST /attachments/from-url | The URL failed the SSRF check -- non-HTTP scheme, private/loopback/link-local IP, hostname doesn't resolve, or one of the resolved IPs is private. | Use a publicly reachable http:// or https:// URL. |
400 Failed to fetch URL | POST /attachments/from-url | The source server returned an error, timed out, or sent a redirect (we don't follow redirects). | Check the source URL is reachable, returns 2xx directly, and responds within 30s. |
400 Source URL returned status N | POST /attachments/from-url | The source returned an HTTP error (e.g. 403, 404). | Verify the URL works in a browser / curl from outside your network. |
400 Source URL returned an empty body | POST /attachments/from-url | The fetch succeeded with status 2xx but the body was zero bytes. | Re-check the URL. |
400 No filename provided | POST /attachments/upload | The multipart upload didn't include a filename. | Set the form field's filename. |
400 File extension '.X' is not allowed | both endpoints | Extension is on the executable / script blocklist. | Don't try to upload .exe, .bat, .sh, .php, .js, etc. |
400 File too large. Maximum size is 50.0MB | both endpoints | Bytes exceed 50 MB cap. | Compress, or split into multiple attachments. |
400 File content doesn't match claimed type 'X' | POST /attachments/upload | The file's magic bytes don't match its declared Content-Type. | Send the correct MIME type. Don't rename files to spoof the extension. |
413 Payload Too Large | POST /attachments/from-url | Source advertised or streamed > 50 MB. | Use a smaller file. |
415 Unsupported Media Type | POST /attachments/from-url | MIME type not on the URL-fetch allowlist. Response body includes allowed_types. | Use /upload (broader allowlist), or convert the file. |
422 Unprocessable Entity | POST /messages | attachments[] contained something that wasn't a UUID -- typically a raw URL. | Call /attachments/from-url first, then pass the returned UUID. |
404 Attachment {id} not found | POST /messages, GET /attachments/{id} | Well-formed UUID but no such attachment exists in your tenant. | Verify the upload succeeded and the UUID is correct. |
403 | any | Token lacks the required scope (messages:create, messages:read, or messages:delete). | Issue a token with the right scopes. |
401 | any | Token missing or invalid. | Check Authorization: Bearer <token> header. |
Example: 415 response body
{
"detail": {
"detail": "Unsupported media type",
"allowed_types": [
"application/pdf",
"audio/mp4",
"audio/mpeg",
"audio/ogg",
"audio/wav",
"audio/x-wav",
"image/gif",
"image/jpeg",
"image/png",
"image/webp",
"video/mp4",
"video/quicktime",
"video/webm"
]
}
}
Example: 422 from messages
{
"detail": [
{
"loc": ["body", "attachments", 0],
"msg": "value is not a valid uuid",
"type": "type_error.uuid"
}
]
}
If you see this, call POST /api/v1/attachments/from-url with your URL first, then send the returned UUID in attachments[].