{"record":{"id":"66fd32fceb4d9c25","repo":"kubernetes/kubernetes","slug":"unable-to-process-a-request-with-a-non-json-conten","errorCode":null,"errorMessage":"unable to process a request with a non-json content type","messagePattern":"unable to process a request with a non-json content type","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go","lineNumber":200,"sourceCode":"\n\tdefer r.Body.Close()\n\tlimitedReader := &io.LimitedReader{R: r.Body, N: maxRequestSize}\n\tif body, err = ioutil.ReadAll(limitedReader); err != nil {\n\t\tlogger.Error(err, \"unable to read the body from the incoming request\")\n\t\thttp.Error(w, \"unable to read the body from the incoming request\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tif limitedReader.N <= 0 {\n\t\tlogger.Error(err, \"unable to read the body from the incoming request; limit reached\")\n\t\thttp.Error(w, fmt.Sprintf(\"request entity is too large; limit is %d bytes\", maxRequestSize), http.StatusRequestEntityTooLarge)\n\t\treturn\n\t}\n\n\t// verify the content type is accurate\n\tif contentType := r.Header.Get(\"Content-Type\"); contentType != \"application/json\" {\n\t\terr = fmt.Errorf(\"contentType=%s, expected application/json\", contentType)\n\t\tlogger.Error(err, \"unable to process a request with an unknown content type\", \"type\", contentType)\n\t\thttp.Error(w, \"unable to process a request with a non-json content type\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tv1AdmissionReviewKind := admissionv1.SchemeGroupVersion.WithKind(\"AdmissionReview\")\n\treviewObject, gvk, err := codecs.UniversalDeserializer().Decode(body, &v1AdmissionReviewKind, nil)\n\tif err != nil {\n\t\tlogger.Error(err, \"unable to decode the request\")\n\t\thttp.Error(w, \"unable to decode the request\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tif *gvk != v1AdmissionReviewKind {\n\t\tlogger.Info(\"Unexpected AdmissionReview kind\", \"kind\", gvk.String())\n\t\thttp.Error(w, fmt.Sprintf(\"unexpected AdmissionReview kind: %s\", gvk.String()), http.StatusBadRequest)\n\t\treturn\n\t}\n\treview, ok := reviewObject.(*admissionv1.AdmissionReview)\n\tif !ok {\n\t\tlogger.Info(\"Failed admissionv1.AdmissionReview type assertion\")","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/kubernetes/kubernetes/blob/b882c60b4023bdf09264c2d5d30a2cadebc240fb/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go#L182-L218","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the header to exactly application/json with no parameters: req.Header.Set(\"Content-Type\", \"application/json\").","If using the apiserver, ensure you are not forcing protobuf serialization onto this webhook — PodSecurity webhook speaks JSON only.","Check intermediaries (mesh, ingress, WAF) for header rewriting and pin Content-Type end-to-end.","When testing, pass -H 'Content-Type: application/json' explicitly to curl."],"exampleFix":"// before: client appends a charset, server rejects\nreq.Header.Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\n// after: exact match the webhook expects\nreq.Header.Set(\"Content-Type\", \"application/json\")","handlingStrategy":"validation","validationCode":"// Caller: set Content-Type exactly. The webhook uses strict equality\n// against \"application/json\" (no charset, no parameters).\nreq.Header.Set(\"Content-Type\", \"application/json\") // exact\nif ct := req.Header.Get(\"Content-Type\"); ct != \"application/json\" {\n    return fmt.Errorf(\"bad content type %q\", ct)\n}","typeGuard":"func isExactJSONContentType(ct string) bool { return ct == \"application/json\" }","tryCatchPattern":"// Client: 400 here is a programmer error; correct the header and resend.\nif resp.StatusCode == 400 && strings.Contains(body, \"non-json content type\") {\n    return fmt.Errorf(\"set Content-Type: application/json exactly (no charset)\")\n}","preventionTips":["Always set Content-Type with req.Header.Set, never req.Header.Add, to avoid duplicates.","Pin intermediaries to forward Content-Type unchanged.","Add an integration test asserting the exact header value.","When using curl, pass -H 'Content-Type: application/json'."],"tags":["webhook","pod-security-admission","content-type","validation","go"],"analyzedSha":"b882c60b4023bdf09264c2d5d30a2cadebc240fb","analyzedAt":"2026-08-07T04:07:48.144Z","schemaVersion":2},"datasetVersion":"2026-08-07T07:17:06.508Z"}