hyperledger/fabric · warning

response Content-Type is application/json only

Error message

response Content-Type is application/json only

What it means

negotiateContentType inspects the request's Accept header and only serves responses as application/json; when no acceptable option matches (no 'application/json', 'application/*', or '*/*'), it returns this error and the caller rejects the request with HTTP 406. The channelparticipation API responds exclusively in JSON, so it refuses any Accept header that explicitly excludes JSON.

Source

Thrown at orderer/common/channelparticipation/restapi.go:662

	h.sendResponseNotAllowed(resp, err, http.MethodGet, http.MethodPost, http.MethodPut)
}

func negotiateContentType(req *http.Request) (string, error) {
	acceptReq := req.Header.Get("Accept")
	if len(acceptReq) == 0 {
		return "application/json", nil
	}

	options := strings.SplitSeq(acceptReq, ",")
	for opt := range options {
		if strings.Contains(opt, "application/json") ||
			strings.Contains(opt, "application/*") ||
			strings.Contains(opt, "*/*") {
			return "application/json", nil
		}
	}

	return "", errors.New("response Content-Type is application/json only")
}

func (h *HTTPHandler) sendResponseJsonError(resp http.ResponseWriter, code int, err error) {
	encoder := json.NewEncoder(resp)
	resp.Header().Set("Content-Type", "application/json")
	resp.WriteHeader(code)
	if err := encoder.Encode(&types.ErrorResponse{Error: err.Error()}); err != nil {
		h.logger.Errorf("failed to encode error, err: %s", err)
	}
}

func (h *HTTPHandler) sendResponseOK(resp http.ResponseWriter, content any) {
	encoder := json.NewEncoder(resp)
	resp.Header().Set("Content-Type", "application/json")
	resp.WriteHeader(http.StatusOK)
	if err := encoder.Encode(content); err != nil {
		h.logger.Errorf("failed to encode content, err: %s", err)
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Set Accept: application/json on the request
  2. Use Accept: */* to accept any type (server will return JSON)
  3. Remove the Accept header entirely so negotiation defaults to JSON
  4. Remove a proxy/gateway-injected Accept header that excludes application/json

Example fix

// before
Accept: text/html
// after
Accept: application/json
Defensive patterns

Strategy: validation

Validate before calling

const accept = headers['Accept'];
if (accept && !/application\/json|application\/\*|\*\/\*/.test(accept)) {
  throw new Error(`channelparticipation serves JSON only; Accept header excludes it: ${accept}`);
}

Type guard

function acceptsJSON(accept: string | undefined): boolean {
  return !accept || /application\/json|application\/\*|\*\/\*/.test(accept);
}

Try / catch

try {
  const res = await fetch(url, { headers: { Accept: 'application/json' } });
  if (res.status === 406) throw new Error('Accept header must allow application/json');
} catch (e) {
  if (String(e).includes('application/json')) console.error('Fix the Accept header and retry');
  else throw e;
}

Prevention

When it happens

Trigger: Any channelparticipation endpoint (list all/one, fetch block, join, update, remove) called with an Accept header such as 'text/html', 'application/xml', or a list that omits application/json and wildcard types.

Common situations: Browsers sending 'Accept: text/html' when hitting the endpoint directly; XML-expecting clients; corporate gateways injecting restrictive Accept headers; clients explicitly setting Accept to a vendor type like application/vnd.api+json.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/148cc0229731730b. Report an issue: GitHub.