{"record":{"id":"f9171a04429c0447","repo":"hyperledger/fabric","slug":"unsupported-content-type-s","errorCode":null,"errorMessage":"unsupported Content-Type: %s","messagePattern":"unsupported Content-Type: (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"orderer/common/channelparticipation/restapi.go","lineNumber":627,"sourceCode":"\t\treturn\n\t}\n\n\th.logger.Debugf(\"Failed to remove channel: %s, err: %s\", channelID, err)\n\n\tswitch err {\n\tcase types.ErrSystemChannelExists:\n\t\th.sendResponseNotAllowed(resp, errors.WithMessage(err, \"cannot remove\"), http.MethodGet)\n\tcase types.ErrChannelNotExist:\n\t\th.sendResponseJsonError(resp, http.StatusNotFound, errors.WithMessage(err, \"cannot remove\"))\n\tcase types.ErrChannelPendingRemoval:\n\t\th.sendResponseJsonError(resp, http.StatusConflict, errors.WithMessage(err, \"cannot remove\"))\n\tdefault:\n\t\th.sendResponseJsonError(resp, http.StatusBadRequest, errors.WithMessage(err, \"cannot remove\"))\n\t}\n}\n\nfunc (h *HTTPHandler) serveBadContentType(resp http.ResponseWriter, req *http.Request) {\n\terr := errors.Errorf(\"unsupported Content-Type: %s\", req.Header.Values(\"Content-Type\"))\n\th.sendResponseJsonError(resp, http.StatusBadRequest, err)\n}\n\nfunc (h *HTTPHandler) serveNotAllowed(resp http.ResponseWriter, req *http.Request) {\n\terr := errors.Errorf(\"invalid request method: %s\", req.Method)\n\n\tif _, ok := mux.Vars(req)[blockIDKey]; ok {\n\t\th.sendResponseNotAllowed(resp, err, http.MethodGet)\n\t\treturn\n\t}\n\n\tif _, ok := mux.Vars(req)[channelIDKey]; ok {\n\t\th.sendResponseNotAllowed(resp, err, http.MethodGet, http.MethodDelete)\n\t\treturn\n\t}\n\n\th.sendResponseNotAllowed(resp, err, http.MethodGet, http.MethodPost, http.MethodPut)\n}","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/channelparticipation/restapi.go#L609-L645","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncurl -X POST http://orderer:7053/participation/channels -d '{...}'\n// after\ncurl -X POST http://orderer:7053/participation/channels -H 'Content-Type: application/json' -d '{...}'","handlingStrategy":"validation","validationCode":"const ct = headers['Content-Type'] ?? headers['content-type'];\nif (!ct || !/^(application\\/json|multipart\\/related)/.test(Array.isArray(ct) ? ct.join(',') : ct)) {\n  throw new Error(`set a supported Content-Type before calling join/update; got: ${ct}`);\n}","typeGuard":"function isSupportedContentType(v: unknown): v is 'application/json' | 'multipart/related' {\n  return typeof v === 'string' && /^(application\\/json|multipart\\/related)/.test(v);\n}","tryCatchPattern":"try {\n  const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body });\n  const out = await res.json();\n  if (!res.ok) throw new Error(out.error ?? `HTTP ${res.status}`);\n} catch (e) {\n  if (String(e).includes('unsupported Content-Type')) console.error('Resend with Content-Type: application/json');\n  else throw e;\n}","preventionTips":["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"],"tags":["http","content-type","rest-api","hyperledger-fabric","orderer"],"backgroundTag":"unsupported-content-type","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}