k3s-io/k3s · error

invalid token format

Error message

invalid token format

What it means

After the optional CA hash is split off, the credential segment must parse either as a kubeadm bootstrap token string (<6-char id>.<16-char secret>) or as basic auth (<username>:<password> with a non-empty password). If neither shape matches, parseToken rejects the input as an invalid token format.

Source

Thrown at pkg/clientaccess/token.go:251

	// Split into CA hash and creds.
	parts := strings.SplitN(token, "::", 2)
	token = parts[0]
	if len(parts) > 1 {
		hashLen := len(parts[0])
		if hashLen > 0 && hashLen != caHashLength {
			return nil, errors.New("invalid token CA hash length")
		}
		info.caHash = parts[0]
		token = parts[1]
	}

	// Try to parse creds as bootstrap token string; fall back to basic auth.
	// If neither works, error.
	bts, err := kubeadm.NewBootstrapTokenString(token)
	if err != nil {
		parts = strings.SplitN(token, ":", 2)
		if len(parts) != 2 || len(parts[1]) == 0 {
			return nil, errors.New("invalid token format")
		}
		info.Username = parts[0]
		info.Password = parts[1]
	} else {
		info.BootstrapTokenString = bts
	}

	return &info, nil
}

// GetHTTPClient returns a http client that validates TLS server certificates using the provided CA bundle.
// If the CA bundle is empty, it validates using the default http client using the OS CA bundle.
// If the CA bundle is not empty but does not contain any valid certs, it validates using
// an empty CA bundle (which will always fail).
// If valid cert+key paths can be loaded from the provided paths, they are used for client cert auth.
func GetHTTPClient(cacerts []byte, certFile, keyFile string, options ...any) *http.Client {
	if len(cacerts) == 0 {
		return defaultClient

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Regenerate the token on the seed server with `k3s token create` and use the exact output
  2. Validate shape before use: creds must match ^[a-z0-9]{6}\.[a-z0-9]{16}$ or ^[^:]+:.+$
  3. Never assemble tokens by string concatenation from parts

Example fix

# before (empty password / malformed creds)
K10::<hash>::admin:

# after
K10::<hash>::abcdef.0123456789abcdef
Defensive patterns

Strategy: validation

Validate before calling

creds := tokenAfterHashSegment // part after '::'
bootstrap := regexp.MustCompile(`^[a-z0-9]{6}\.[a-z0-9]{16}$`)
basic := regexp.MustCompile(`^[^:\s]+:.+$`)
if !bootstrap.MatchString(creds) && !basic.MatchString(creds) {
    return fmt.Errorf("invalid token format: %q", creds)
}

Type guard

func isK3sCredsSegment(creds string) bool {
    bootstrap := regexp.MustCompile(`^[a-z0-9]{6}\.[a-z0-9]{16}$`)
    basic := regexp.MustCompile(`^[^:\s]+:.+$`)
    return bootstrap.MatchString(creds) || basic.MatchString(creds)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "invalid token format") {
    return fmt.Errorf("join token malformed; regenerate with `k3s token create` on the seed server")
}

Prevention

When it happens

Trigger: Tokens like `K10::<user>:` (empty password after the colon), `K10::justarandomstring`, or credentials where the '::' vs ':' separators got collapsed/reordered during transcription.

Common situations: Hand-editing tokens; scripts that join server URL and token with the wrong separator; credentials rotated into a secret with a missing field; pasting only the ID portion of a bootstrap token.

Understand the failure class

Related errors


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