kubernetes/kops · error

failed to convert server ID

Error message

failed to convert server ID %q to int: %w

What it means

VerifyToken strips the "hcloud://"-style prefix from the presented bootstrap token and parses the remainder as the numeric Hetzner server ID. If the token body isn't a valid int64, parsing fails and the token is rejected. This means the presented token is malformed for this verifier.

Solutions

  1. Regenerate the token on the Hetzner node using the hetznermetadata authenticator (ensure instance metadata works there).
  2. Log/inspect the presented token (after prefix) to see why it isn't numeric.
  3. Ensure the node uses the Hetzner bootstrap authenticator matching this verifier.
  4. Check for token truncation/corruption in whatever passes the token (config, header).
Defensive patterns

Strategy: type-guard

Validate before calling

body := strings.TrimPrefix(token, hetznermetadata.HetznerAuthenticationTokenPrefix)
if _, err := strconv.ParseInt(body, 10, 64); err != nil {
  return nil, bootstrap.ErrNotThisVerifier // malformed: not a Hetzner token
}

Type guard

func isHetznerToken(token string) bool {
  body := strings.TrimPrefix(token, hetznermetadata.HetznerAuthenticationTokenPrefix)
  _, err := strconv.ParseInt(body, 10, 64)
  return err == nil && body != ""
}

Prevention

When it happens

Trigger: A node presents a token whose payload after the prefix is non-numeric (empty, truncated, from a different verifier/provider, or manually forged/edited).

Common situations: Token generated on a non-Hetzner environment (metadata lookup failed earlier and produced a bad token); token truncated in transport; using a token from a different kOps cloud provider.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/08d0da34f5a9400f. Report an issue: GitHub.

Appendix: source

Thrown at upup/pkg/fi/cloudup/hetzner/verifier.go:71

		hcloud.WithApplication("kops", version.Version),
	}
	hcloudClient := hcloud.NewClient(opts...)

	return &hetznerVerifier{
		opt:    *opt,
		client: hcloudClient,
	}, nil
}

func (h hetznerVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
	if !strings.HasPrefix(token, hetznermetadata.HetznerAuthenticationTokenPrefix) {
		return nil, bootstrap.ErrNotThisVerifier
	}
	token = strings.TrimPrefix(token, hetznermetadata.HetznerAuthenticationTokenPrefix)

	serverID, err := strconv.ParseInt(token, 10, 64)
	if err != nil {
		return nil, fmt.Errorf("failed to convert server ID %q to int: %w", token, err)
	}
	server, _, err := h.client.Server.GetByID(ctx, serverID)
	if err != nil || server == nil {
		return nil, fmt.Errorf("failed to get info for server %q: %w", token, err)
	}

	var addrs []string
	var challengeEndpoints []string
	if server.PublicNet.IPv4.IP != nil {
		// Don't challenge over the public network
		addrs = append(addrs, server.PublicNet.IPv4.IP.String())
	}
	for _, network := range server.PrivateNet {
		if network.IP != nil {
			addrs = append(addrs, network.IP.String())
			challengeEndpoints = append(challengeEndpoints, net.JoinHostPort(network.IP.String(), strconv.Itoa(wellknownports.NodeupChallenge)))
		}
	}

View on GitHub (pinned to 4c8573c808)