zitadel/zitadel · error
invalid content-type: %s
Error message
invalid content-type: %s
What it means
The asset upload handler sniffs the uploaded file's MIME type and checks it against the uploader's allowed content types (ContentTypeAllowed). If the detected type is not allowed, the request is rejected with 400 'invalid content-type'.
Source
Thrown at internal/api/assets/asset.go:176
defer func() {
err = file.Close()
logging.OnError(err).Warn("could not close file")
}()
mimeType, err := mimetype.DetectReader(file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
size := handler.Size
if !uploader.ContentTypeAllowed(mimeType.String()) {
s.ErrorHandler()(w, r, fmt.Errorf("invalid content-type: %s", mimeType), http.StatusBadRequest)
return
}
if size > uploader.MaxFileSize() {
s.ErrorHandler()(w, r, fmt.Errorf("file too big, max file size is %vKB", uploader.MaxFileSize()/1024), http.StatusBadRequest)
return
}
resourceOwner := uploader.ResourceOwner(authz.GetInstance(ctx), ctxData)
objectName, err := uploader.ObjectName(ctxData)
if err != nil {
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
return
}
uploadInfo := &command.AssetUpload{
ResourceOwner: resourceOwner,
ObjectName: objectName,
ContentType: mimeType.String(),
ObjectType: uploader.ObjectType(),View on GitHub (pinned to 13948f2bcd)
Solutions
- Upload a file whose MIME type matches the endpoint's allowed list (e.g. PNG/JPEG for logos)
- Send a proper multipart/form-data request with the file part
- Check the specific uploader's allowed content types (e.g. internal/api/assets) and convert/serve the asset accordingly
Example fix
// before curl -F "file=logo.svg" $HOST/assets/v1/instance // after convert logo.svg logo.png curl -F "file=@logo.png" $HOST/assets/v1/instance
Defensive patterns
Strategy: validation
Validate before calling
const allowed = ["image/png", "image/jpeg", "image/webp"];
const file = formData.get("file");
if (!allowed.includes(file.type)) throw new Error(`content-type ${file.type} not allowed; use one of ${allowed.join(", ")}`); Type guard
function isAllowedMime(t, allowed) { return allowed.includes(t); } Try / catch
try {
await uploadAsset(file);
} catch (e) {
if (e.status === 400 && e.message.includes("invalid content-type")) {
// convert the file to an allowed type and retry once
}
} Prevention
- Check the endpoint's allowed content types before integrating uploads
- Convert SVGs to PNG/JPEG client-side for logo endpoints
- Send real multipart file parts, not raw JSON bodies, so server-side sniffing sees the right type
When it happens
Trigger: Uploading an asset (logo, icon, user avatar via /assets/v1 endpoints) whose detected MIME type is not in the uploader's allowed list, e.g. uploading an SVG to an endpoint that only accepts PNG/JPEG, or sending a text file where an image is required.
Common situations: Uploading files with wrong extensions after renaming; brand logos supplied as SVG when the endpoint only permits raster images; API clients sending JSON instead of multipart file data so the sniffed type is wrong.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- file too big, max file size is %vKB
- upload failed: %v
- invalid request URI format: %v
- download failed: %v
- file not found: %v
AI-assisted analysis of zitadel/zitadel@13948f2bcd (2026-09-06).
Data as JSON: /api/errors/844d8bef1f0be332.
Report an issue: GitHub.