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

  1. Replace raw strings with the exported constants: services.APIServer, services.Kubelet, services.ETCD, services.AuthProxy, ...
  2. Validate before calling: for each name check services.IsValid(s) and reject early
  3. 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

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


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/bd749ac643d12194. Report an issue: GitHub.