hyperledger/fabric · warning
unsupported Content-Type: %s
Error message
unsupported Content-Type: %s
What it means
serveBadContentType fires when a request that requires a body (join or update) arrives without an accepted Content-Type header. The handler rejects it with HTTP 400 and an 'unsupported Content-Type' message listing what was sent. The API only accepts specific Content-Types for channel join/update payloads.
Source
Thrown at orderer/common/channelparticipation/restapi.go:627
return
}
h.logger.Debugf("Failed to remove channel: %s, err: %s", channelID, err)
switch err {
case types.ErrSystemChannelExists:
h.sendResponseNotAllowed(resp, errors.WithMessage(err, "cannot remove"), http.MethodGet)
case types.ErrChannelNotExist:
h.sendResponseJsonError(resp, http.StatusNotFound, errors.WithMessage(err, "cannot remove"))
case types.ErrChannelPendingRemoval:
h.sendResponseJsonError(resp, http.StatusConflict, errors.WithMessage(err, "cannot remove"))
default:
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.WithMessage(err, "cannot remove"))
}
}
func (h *HTTPHandler) serveBadContentType(resp http.ResponseWriter, req *http.Request) {
err := errors.Errorf("unsupported Content-Type: %s", req.Header.Values("Content-Type"))
h.sendResponseJsonError(resp, http.StatusBadRequest, err)
}
func (h *HTTPHandler) serveNotAllowed(resp http.ResponseWriter, req *http.Request) {
err := errors.Errorf("invalid request method: %s", req.Method)
if _, ok := mux.Vars(req)[blockIDKey]; ok {
h.sendResponseNotAllowed(resp, err, http.MethodGet)
return
}
if _, ok := mux.Vars(req)[channelIDKey]; ok {
h.sendResponseNotAllowed(resp, err, http.MethodGet, http.MethodDelete)
return
}
h.sendResponseNotAllowed(resp, err, http.MethodGet, http.MethodPost, http.MethodPut)
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Set the header explicitly: Content-Type: application/json (or multipart/related when submitting a config block for join)
- Inspect req.Header.Values('Content-Type') reported in the message and correct it to a supported type
- Remove duplicate/malformed Content-Type headers that produce an unexpected value list
- Update the client library/SDK to one that sets the correct Content-Type for channelparticipation endpoints
Example fix
// before
curl -X POST http://orderer:7053/participation/channels -d '{...}'
// after
curl -X POST http://orderer:7053/participation/channels -H 'Content-Type: application/json' -d '{...}' Defensive patterns
Strategy: validation
Validate before calling
const ct = headers['Content-Type'] ?? headers['content-type'];
if (!ct || !/^(application\/json|multipart\/related)/.test(Array.isArray(ct) ? ct.join(',') : ct)) {
throw new Error(`set a supported Content-Type before calling join/update; got: ${ct}`);
} Type guard
function isSupportedContentType(v: unknown): v is 'application/json' | 'multipart/related' {
return typeof v === 'string' && /^(application\/json|multipart\/related)/.test(v);
} Try / catch
try {
const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body });
const out = await res.json();
if (!res.ok) throw new Error(out.error ?? `HTTP ${res.status}`);
} catch (e) {
if (String(e).includes('unsupported Content-Type')) console.error('Resend with Content-Type: application/json');
else throw e;
} Prevention
- Always set Content-Type: application/json on join/update requests
- Use multipart/related only when submitting a join body containing a config block
- Check the error message echoes your header values to catch duplicates
- Do not let HTTP clients default to text/plain or x-www-form-urlencoded
When it happens
Trigger: POST /participation/channels (join) or PUT /participation/channels/{id} (update) sent with no Content-Type, or with a Content-Type other than the supported application/json (or multipart/related for join with config block), so the switch in the content-type dispatch falls to the default case.
Common situations: curl -d without -H 'Content-Type: application/json'; HTTP clients defaulting to text/plain or application/x-www-form-urlencoded; sending form data instead of a JSON join body; clients omitting the header on empty-body join requests that still require the type.
Related errors
- missing channel ID
- missing block ID
- invalid request method: %s
- cannot parse Mime media type
- response Content-Type is application/json only
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f9171a04429c0447.
Report an issue: GitHub.