kubernetes/kubernetes · warning
nil EndpointSlice passed to serviceControllerKey()
Error message
nil EndpointSlice passed to serviceControllerKey()
What it means
Emitted by endpointsControllerKey when called with a nil EndpointSlice pointer. The function derives a namespace/name key from the EndpointSlice to queue the corresponding Endpoints resource for reconciliation. A nil slice has no namespace or labels, so the key cannot be derived.
Source
Thrown at pkg/controller/endpointslicemirroring/utils.go:218
// state is unrecorded.
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
return nil
}
endpointSlice, ok := tombstone.Obj.(*discovery.EndpointSlice)
if !ok {
utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not an EndpointSlice resource: %#v", obj))
return nil
}
return endpointSlice
}
// endpointsControllerKey returns a controller key for an Endpoints resource but
// derived from an EndpointSlice.
func endpointsControllerKey(endpointSlice *discovery.EndpointSlice) (string, error) {
if endpointSlice == nil {
return "", fmt.Errorf("nil EndpointSlice passed to serviceControllerKey()")
}
serviceName, ok := endpointSlice.Labels[discovery.LabelServiceName]
if !ok || serviceName == "" {
return "", fmt.Errorf("EndpointSlice missing %s label", discovery.LabelServiceName)
}
return fmt.Sprintf("%s/%s", endpointSlice.Namespace, serviceName), nil
}
// skipMirror return true if the LabelSkipMirror label has been set to
// "true".
func skipMirror(labels map[string]string) bool {
skipMirror, _ := labels[discovery.LabelSkipMirror]
return skipMirror == "true"
}
// hasLeaderElection returns true if the LeaderElectionRecordAnnotationKey is
// set as an annotation.
func hasLeaderElection(annotations map[string]string) bool {View on GitHub (pinned to 94c1367642)
Solutions
- Ensure callers check endpointSlice != nil before calling endpointsControllerKey.
- In tests, always pass a valid *discovery.EndpointSlice.
- If seen in production, trace the call stack to find which code path skipped the nil guard.
- The controller already handles this gracefully by logging and returning.
Example fix
// before
key, err := endpointsControllerKey(nil)
// after
if endpointSlice == nil {
return
}
key, err := endpointsControllerKey(endpointSlice) Defensive patterns
Strategy: validation
Validate before calling
if endpointSlice == nil {
// skip calling endpointsControllerKey
return
} Type guard
func isNonNilEndpointSlice(slice *discovery.EndpointSlice) bool {
return slice != nil
} Prevention
- Always nil-check before calling endpointsControllerKey.
- In tests, pass valid *discovery.EndpointSlice instances.
- Ensure upstream callers (queueEndpointsForEndpointSlice) retain their nil guards.
When it happens
Trigger: queueEndpointsForEndpointSlice is called with a nil *discovery.EndpointSlice. This should not happen in normal flow since callers check for nil before calling, but could occur if a code path or test invokes endpointsControllerKey directly with nil.
Common situations: Direct unit tests of endpointsControllerKey passing nil. A logic bug where a nil check is skipped before calling the function. Extremely unlikely in production given the controller's nil guards upstream.
Related errors
- onEndpointSliceAdd() expected type discovery.EndpointSlice,
- onEndpointSliceUpdated() expected type discovery.EndpointSli
- onEndpointSliceDelete() expected type discovery.EndpointSlic
- Couldn't get key for EndpointSlice %+v (type %T): %v
- tombstone contained object that is not an EndpointSlice reso
AI-assisted analysis of kubernetes/kubernetes@94c1367642 (2026-08-08).
Data as JSON: /api/errors/cb0e9f80a7df2388.
Report an issue: GitHub.