k3s-io/k3s · error
%s is not a recognized service
Error message
%s is not a recognized service
What it means
FilesForServices maps each requested service name to its certificate/key file list; the switch recognizes only the package constants (api-server, admin, auth-proxy, certificate-authority, cloud-controller, controller-manager, etcd, kube-proxy, kubelet, scheduler, supervisor, plus <program>-controller and <program>-server built from version.Program). Any other string hits the default branch. The exported constants and services.IsValid exist precisely to avoid this.
Source
Thrown at pkg/util/services/services.go:147
filepath.Join(agentDataDir, "client-kube-proxy.key"),
}
case CertificateAuthority:
fileMap[service] = []string{
controlConfig.Runtime.ServerCA,
controlConfig.Runtime.ServerCAKey,
controlConfig.Runtime.ClientCA,
controlConfig.Runtime.ClientCAKey,
controlConfig.Runtime.RequestHeaderCA,
controlConfig.Runtime.RequestHeaderCAKey,
controlConfig.Runtime.ETCDPeerCA,
controlConfig.Runtime.ETCDPeerCAKey,
controlConfig.Runtime.ETCDServerCA,
controlConfig.Runtime.ETCDServerCAKey,
}
case version.Program + ProgramServer:
// not handled here, as the dynamiclistener cert cache is not a standard cert
default:
return nil, fmt.Errorf("%s is not a recognized service", service)
}
}
return fileMap, nil
}
func IsValid(svc string) bool {
for _, service := range All {
if svc == service {
return true
}
}
return false
}
View on GitHub (pinned to 6ba341e396)
Solutions
- Replace raw strings with the exported constants: services.APIServer, services.Kubelet, services.ETCD, services.AuthProxy, ...
- Validate before calling: for each name check services.IsValid(s) and reject early
- Print or inspect services.All in your version for the exact accepted names before constructing the list
Example fix
// before
m, err := services.FilesForServices(cfg, []string{"kube-apiserver", "kubelet"})
// after
m, err := services.FilesForServices(cfg, []string{services.APIServer, services.Kubelet}) Defensive patterns
Strategy: type-guard
Validate before calling
for _, svc := range requested {
if !services.IsValid(svc) {
return fmt.Errorf("unknown service %q; valid: %v", svc, services.All)
}
}
fileMap, err := services.FilesForServices(controlConfig, requested) Type guard
func isKnownService(svc string) bool { return services.IsValid(svc) }
// note: services.IsValid checks services.All and does NOT include
// services.CertificateAuthority ("certificate-authority"), even though
// FilesForServices accepts it - pass that constant directly if needed. Try / catch
fileMap, err := services.FilesForServices(cfg, svcs)
if err != nil {
if strings.Contains(err.Error(), "is not a recognized service") {
// a name in the list is wrong: compare against services.All and fix the input
return nil, fmt.Errorf("%w (valid names: %v)", err, services.All)
}
return nil, err
} Prevention
- Always use the exported constants (services.APIServer, services.Kubelet, ...) instead of raw strings
- Validate user-supplied service names with services.IsValid before building the list
- Re-check service name constants when upgrading - names derive from version.Program
When it happens
Trigger: Calling services.FilesForServices with raw strings like "kube-apiserver" (the constant value is "api-server"), a typo, or a service name from a different version's naming scheme.
Common situations: Using raw strings instead of the exported constants; configs or scripts copied from older versions where names differed; passing user-supplied service lists (e.g. from a cert-rotation command) into the function without validation.
Related errors
- invalid node-ip: %w
- critical configuration value mismatch between servers
- no certificates loaded from etcd-s3-endpoint-ca
- method not allowed
- new CA bundle contains only a single certificate but should
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/bd749ac643d12194.
Report an issue: GitHub.