{"record":{"id":"f3bd6ea40a63092e","repo":"k3s-io/k3s","slug":"token-must-not-be-empty","errorCode":null,"errorMessage":"token must not be empty","messagePattern":"token must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/clientaccess/token.go","lineNumber":216,"sourceCode":"// along with a bool indicating if the token was successfully parsed.\n// Kubeadm-style tokens have ID/Secret not Username/Password and therefore will return false (invalid).\nfunc ParseUsernamePassword(token string) (string, string, bool) {\n\tinfo, err := parseToken(token)\n\tif err != nil {\n\t\treturn \"\", \"\", false\n\t}\n\tif info.BootstrapTokenString != nil {\n\t\treturn \"\", \"\", false\n\t}\n\treturn info.Username, info.Password, true\n}\n\n// parseToken parses a token into an Info struct\nfunc parseToken(token string) (*Info, error) {\n\tvar info Info\n\n\tif len(token) == 0 {\n\t\treturn nil, errors.New(\"token must not be empty\")\n\t}\n\n\t// Turn bare password or bootstrap token into full K10 token with empty CA hash,\n\t// for consistent parsing in the section below.\n\tif !strings.HasPrefix(token, tokenPrefix) {\n\t\t_, err := kubeadm.NewBootstrapTokenString(token)\n\t\tif err != nil {\n\t\t\ttoken = tokenPrefix + \":::\" + token\n\t\t} else {\n\t\t\ttoken = tokenPrefix + \"::\" + token\n\t\t}\n\t}\n\n\t// Strip off the prefix.\n\ttoken = token[len(tokenPrefix):]\n\n\t// Split into CA hash and creds.\n\tparts := strings.SplitN(token, \"::\", 2)","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/clientaccess/token.go#L198-L234","documentation":"clientaccess.parseToken (reached through ParseAndValidateToken / NewAccessInfo when joining a server or agent) rejects the empty string before doing any format work. It exists so callers fail fast with a clear message instead of proceeding with anonymous access.","triggerScenarios":"Calling clientaccess.ParseAndValidateToken(serverURL, \"\") in Go, or starting k3s with `--server <url>` while K3S_TOKEN/--token is empty (or the config `token:` key is an empty string).","commonSituations":"K3S_TOKEN exported but set to empty (`K3S_TOKEN=` in a unit file); config.yaml containing `token: \"\"`; secrets mounted for the token that are empty on first rollout.","solutions":["Provide a valid token: read it from the seed server's /var/lib/rancher/k3s/server/token or generate one with `k3s token create`","Verify the env/secret actually carries a value: `[ -n \"$K3S_TOKEN\" ] && echo set`","In Go callers, guard with a non-empty check before calling ParseAndValidateToken"],"exampleFix":"// before\ninfo, err := clientaccess.ParseAndValidateToken(serverURL, os.Getenv(\"K3S_TOKEN\"))\n\n// after\ntoken := strings.TrimSpace(os.Getenv(\"K3S_TOKEN\"))\nif token == \"\" {\n    return errors.New(\"K3S_TOKEN must be set when joining\")\n}\ninfo, err := clientaccess.ParseAndValidateToken(serverURL, token)","handlingStrategy":"validation","validationCode":"token := strings.TrimSpace(cfg.Token)\nif token == \"\" {\n    return fmt.Errorf(\"token must not be empty when joining %s\", cfg.JoinURL)\n}\ninfo, err := clientaccess.ParseAndValidateToken(cfg.JoinURL, token)","typeGuard":"func isNonEmptyToken(token string) bool { return strings.TrimSpace(token) != \"\" }","tryCatchPattern":"// parseToken errors are plain strings; match on content only after non-nil check\ninfo, err := clientaccess.ParseAndValidateToken(server, token)\nif err != nil {\n    if strings.Contains(err.Error(), \"token must not be empty\") {\n        return errors.New(\"join token missing: check K3S_TOKEN/secret injection\")\n    }\n    return err\n}","preventionTips":["Gate startup on token presence before calling clientaccess APIs","Mount tokens from secrets/files rather than trusting env inheritance","Add readiness checks that fail fast when token secrets are empty"],"tags":["token","validation","api","clientaccess"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}