kubernetes/kubernetes · warning

unable to process a request with a non-json content type

Error message

unable to process a request with a non-json content type

What it means

400 Bad Request at server.go:197-201 returned when Content-Type is anything other than exactly 'application/json' (strict string equality on r.Header.Get). The check is case- and whitespace-sensitive: 'application/json; charset=utf-8', 'Application/JSON', or a missing header all fail. Content type is verified after body size but before decoding.

Source

Thrown at staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go:200

	defer r.Body.Close()
	limitedReader := &io.LimitedReader{R: r.Body, N: maxRequestSize}
	if body, err = ioutil.ReadAll(limitedReader); err != nil {
		logger.Error(err, "unable to read the body from the incoming request")
		http.Error(w, "unable to read the body from the incoming request", http.StatusBadRequest)
		return
	}
	if limitedReader.N <= 0 {
		logger.Error(err, "unable to read the body from the incoming request; limit reached")
		http.Error(w, fmt.Sprintf("request entity is too large; limit is %d bytes", maxRequestSize), http.StatusRequestEntityTooLarge)
		return
	}

	// verify the content type is accurate
	if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
		err = fmt.Errorf("contentType=%s, expected application/json", contentType)
		logger.Error(err, "unable to process a request with an unknown content type", "type", contentType)
		http.Error(w, "unable to process a request with a non-json content type", http.StatusBadRequest)
		return
	}

	v1AdmissionReviewKind := admissionv1.SchemeGroupVersion.WithKind("AdmissionReview")
	reviewObject, gvk, err := codecs.UniversalDeserializer().Decode(body, &v1AdmissionReviewKind, nil)
	if err != nil {
		logger.Error(err, "unable to decode the request")
		http.Error(w, "unable to decode the request", http.StatusBadRequest)
		return
	}
	if *gvk != v1AdmissionReviewKind {
		logger.Info("Unexpected AdmissionReview kind", "kind", gvk.String())
		http.Error(w, fmt.Sprintf("unexpected AdmissionReview kind: %s", gvk.String()), http.StatusBadRequest)
		return
	}
	review, ok := reviewObject.(*admissionv1.AdmissionReview)
	if !ok {
		logger.Info("Failed admissionv1.AdmissionReview type assertion")

View on GitHub (pinned to b882c60b40)

Solutions

  1. Set the header to exactly application/json with no parameters: req.Header.Set("Content-Type", "application/json").
  2. If using the apiserver, ensure you are not forcing protobuf serialization onto this webhook — PodSecurity webhook speaks JSON only.
  3. Check intermediaries (mesh, ingress, WAF) for header rewriting and pin Content-Type end-to-end.
  4. When testing, pass -H 'Content-Type: application/json' explicitly to curl.

Example fix

// before: client appends a charset, server rejects
req.Header.Set("Content-Type", "application/json; charset=utf-8")

// after: exact match the webhook expects
req.Header.Set("Content-Type", "application/json")
Defensive patterns

Strategy: validation

Validate before calling

// Caller: set Content-Type exactly. The webhook uses strict equality
// against "application/json" (no charset, no parameters).
req.Header.Set("Content-Type", "application/json") // exact
if ct := req.Header.Get("Content-Type"); ct != "application/json" {
    return fmt.Errorf("bad content type %q", ct)
}

Type guard

func isExactJSONContentType(ct string) bool { return ct == "application/json" }

Try / catch

// Client: 400 here is a programmer error; correct the header and resend.
if resp.StatusCode == 400 && strings.Contains(body, "non-json content type") {
    return fmt.Errorf("set Content-Type: application/json exactly (no charset)")
}

Prevention

When it happens

Trigger: Calling the webhook with Content-Type application/json; charset=utf-8 (common from some HTTP clients); sending protobuf or yaml; a client defaulting to text/plain; a proxy that rewrites or strips Content-Type; the apiserver misconfigured to call a webhook with a non-JSON content type.

Common situations: Using a generic HTTP client or gRPC-gateway that appends a charset parameter; manually testing with curl without -H 'Content-Type: application/json'; a service mesh/ingress normalizing headers; mismatch between the webhook's expected format and what a custom admission sender emits.

Related errors


AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07). Data as JSON: /api/errors/66fd32fceb4d9c25. Report an issue: GitHub.