k3s-io/k3s · error
--token is required
Error message
--token is required
What it means
Agent bootstrap requires either a valid join token or an already-issued client-kubelet certificate pair from a previous join. The check first attempts tls.LoadX509KeyPair on <data-dir>/agent/client-kubelet.crt/key; only if those are missing/invalid AND no --token/--token-file was provided does it fail. So the error means: first run without a token, or a wiped data-dir on rejoin without re-supplying credentials.
Source
Thrown at pkg/cli/agent/agent.go:83
if err := permissions.IsPrivileged(); err != nil {
return errors.WithMessage(err, "agent requires additional privilege if not run with --rootless")
}
}
if cmds.AgentConfig.TokenFile != "" {
token, err := util.ReadFile(ctx, cmds.AgentConfig.TokenFile)
if err != nil {
return err
}
cmds.AgentConfig.Token = token
}
clientKubeletCert := filepath.Join(cmds.AgentConfig.DataDir, "agent", "client-kubelet.crt")
clientKubeletKey := filepath.Join(cmds.AgentConfig.DataDir, "agent", "client-kubelet.key")
_, err := tls.LoadX509KeyPair(clientKubeletCert, clientKubeletKey)
if err != nil && cmds.AgentConfig.Token == "" {
return errors.New("--token is required")
}
if cmds.AgentConfig.ServerURL == "" {
return errors.New("--server is required")
}
if cmds.AgentConfig.FlannelIface != "" && len(cmds.AgentConfig.NodeIP.Value()) == 0 {
ip, err := util.GetIPFromInterface(cmds.AgentConfig.FlannelIface)
if err != nil {
return err
}
cmds.AgentConfig.NodeIP.Set(ip)
}
logrus.Info("Starting " + version.Program + " agent " + clx.App.Version)
dataDir, err := datadir.LocalHome(cmds.AgentConfig.DataDir, cmds.AgentConfig.Rootless)
if err != nil {View on GitHub (pinned to 6ba341e396)
Solutions
- Get the token from the server (cat /var/lib/rancher/k3s/server/token) and pass it: k3s agent --token <token> --server https://<server>:6443
- Or persist it via --token-file / K3S_TOKEN_FILE so restarts don't depend on flags
- If this is a rejoin after wiping the data-dir, supply the token again — the old client cert no longer exists
Example fix
# before k3s agent --server https://10.0.0.10:6443 # no token, no cached cert -> --token is required # after K3S_TOKEN=K10...::server:... k3s agent --server https://10.0.0.10:6443
Defensive patterns
Strategy: validation
Validate before calling
func hasBootstrapCreds(dataDir string, token string) error {
cert := filepath.Join(dataDir, "agent", "client-kubelet.crt")
key := filepath.Join(dataDir, "agent", "client-kubelet.key")
if _, err := tls.LoadX509KeyPair(cert, key); err == nil { return nil } // cached creds OK
if strings.TrimSpace(token) == "" { return errors.New("provide --token (from /var/lib/rancher/k3s/server/token) on first join") }
return nil
} Prevention
- Automate token distribution from the server into a root-only token file
- After wiping a node's data-dir, always re-supply the token
- Monitor for empty token-file reads (permissions) in provisioning scripts
When it happens
Trigger: First `k3s agent` run with no --token, --token-file, or K3S_TOKEN; data-dir was deleted/corrupted so the cached kubelet client cert is gone and no token is passed; token file path pointing to an empty file that still yields empty Token.
Common situations: New node provisioning where the token secret was not distributed; rejoining after rm -rf /var/lib/rancher/k3s without updating the agent unit; token file with wrong permissions read as empty.
Related errors
- --server is required
- missing argument; 'token delete' is missing token
- token is required to join a cluster
- no bootstrap data found in datastore - check server token va
- found multiple bootstrap keys in storage
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/7c46d11128d04380.
Report an issue: GitHub.