kubernetes/kubernetes · error
err.Error()
Error message
err.Error()
What it means
500 Internal Server Error at server.go:317, the fallback inside writeResponse when json.NewEncoder(w).Encode(review) fails (the encode error is logged at server.go:315 and then its .Error() string is sent to the client). Encoding fails when the AdmissionResponse cannot be JSON-serialized — typically because a nested Status or Warning carries a non-marshalable field, or the response was already partially written and the connection broke.
Source
Thrown at staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go:317
}
if err := s.delegate.CompleteConfiguration(); err != nil {
return nil, fmt.Errorf("configuration error: %w", err)
}
if err := s.delegate.ValidateConfiguration(); err != nil {
return nil, fmt.Errorf("invalid configuration: %w", err)
}
return s, nil
}
func writeResponse(w http.ResponseWriter, review *admissionv1.AdmissionReview) {
// Webhooks should always respond with a 200 HTTP status code when an AdmissionResponse can be sent.
// In an error case, the true status code is captured in the response.result.code
if err := json.NewEncoder(w).Encode(review); err != nil {
klog.ErrorS(err, "Failed to encode response")
// Unable to send an AdmissionResponse, fall back to an HTTP error.
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// parseTimeout parses the given HTTP request URL and extracts the timeout query parameter
// value if specified by the user.
// If a timeout is not specified the function returns false and err is set to nil
// If the value specified is malformed then the function returns false and err is set
func parseTimeout(req *http.Request) (time.Duration, bool, error) {
value := req.URL.Query().Get("timeout")
if value == "" {
return 0, false, nil
}
timeout, err := time.ParseDuration(value)
if err != nil {
return 0, false, fmt.Errorf("invalid timeout query: %w", err)
}
View on GitHub (pinned to b882c60b40)
Solutions
- Check the webhook logs for the 'Failed to encode response' line — it carries the underlying encode error.
- Verify the AdmissionResponse returned by the delegate is a plain admissionv1.AdmissionResponse without custom/non-serializable fields.
- Ensure the apiserver's webhook timeout (timeoutSeconds) is not shorter than the time the webhook needs to respond.
- If the client is closing early, investigate apiserver-side cancellation (context deadline, request aborted).
- Buffer the response before writing (encode to a bytes.Buffer first, then w.Write) so a mid-encode failure does not leave a half-written body — though the upstream code encodes directly to w.
Example fix
// before: encode straight to the ResponseWriter; a mid-encode error
// leaves a half-written body and only then calls http.Error
func writeResponse(w http.ResponseWriter, review *admissionv1.AdmissionReview) {
if err := json.NewEncoder(w).Encode(review); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// after: buffer so encode failures surface before any bytes are sent
func writeResponse(w http.ResponseWriter, review *admissionv1.AdmissionReview) {
buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(review); err != nil {
klog.ErrorS(err, "Failed to encode response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(buf.Bytes())
} Defensive patterns
Strategy: try-catch
Validate before calling
// Server-side hardening: encode into a buffer first so an encode failure
// never leaves a half-written response.
func safeWriteResponse(w http.ResponseWriter, review *admissionv1.AdmissionReview) error {
buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(review); err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
_, err := w.Write(buf.Bytes())
return err
} Type guard
// Ensure the response is JSON-serializable before touching the wire.
func isSerializable(review *admissionv1.AdmissionReview) error {
if _, err := json.Marshal(review); err != nil {
return fmt.Errorf("response not serializable: %w", err)
}
return nil
} Try / catch
// Server: log encode errors and fall back cleanly; never panic.
if err := safeWriteResponse(w, review); err != nil {
klog.ErrorS(err, "Failed to encode response")
if !headersWritten(w) {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
} Prevention
- Buffer-encode before writing to avoid half-written bodies.
- Do not inject custom/non-serializable fields into AdmissionResponse.
- Size the apiserver webhook timeout generously.
- Watch the 'Failed to encode response' log line as an SLO signal.
When it happens
Trigger: json.Encode returns an error mid-write (connection closed by client, response already started); a response field of an unsupported Go type slipped into the AdmissionReview; extremely large response objects; a Status with custom fields not understood by the encoder.
Common situations: Client (apiserver) cancelling the webhook call right after the response starts streaming; a custom evaluator that injects non-serializable data; webhook behind a proxy with a short response timeout; concurrent close during graceful shutdown.
Related errors
- internal server error
- request body is empty
- unable to read the body from the incoming request
- request entity is too large; limit is %d bytes
- unable to process a request with a non-json content type
AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07).
Data as JSON: /api/errors/779890ce35de0c01.
Report an issue: GitHub.