kubernetes/kops · error

failed to get info for server %q: %w

Error message

failed to get info for server %q: %w

What it means

In the kOps Hetzner bootstrap-token verifier (VerifyToken), after stripping the hcloud:// prefix, the token is treated as a Hetzner server ID and fetched via hcloud client.Server.GetByID. This error is returned when the API call fails OR the API returns nil for the server (i.e., no server exists with that ID), meaning kOps could not verify the requesting node as a real Hetzner server. It wraps the underlying hcloud error, so transient API/auth failures and 'server not found' both surface here.

Source

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

	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)))
		}
	}

	if len(challengeEndpoints) == 0 {
		return nil, fmt.Errorf("cannot determine challenge endpoint for server %d", serverID)
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Confirm the server ID in the token exists in the Hetzner project bound to HCLOUD_TOKEN (hcloud server list); delete the stale token entry or re-register the node so a fresh token with the correct server ID is issued.
  2. Verify HCLOUD_TOKEN on the verifier side is valid and has read permission for servers; regenerate the token in the Hetzner Cloud console if needed.
  3. Check connectivity/rate limits to api.hetzner.cloud from the control plane and inspect the wrapped %w error for the root cause (401 vs 404 vs timeout).

Example fix

// debugging the wrapped cause
if _, _, err := client.Server.GetByID(ctx, serverID); err != nil {
    if hcloud.IsError(err, hcloud.ErrorCodeNotFound) {
        // token references a server that no longer exists; re-issue node bootstrap token
    }
}
// before: opaque failure
return nil, fmt.Errorf("failed to get info for server %q: %w", token, err)
// after: distinguish not-found from transient API errors
if err != nil && hcloud.IsError(err, hcloud.ErrorCodeNotFound) {
    return nil, fmt.Errorf("server %q not found in this Hetzner project; re-register the node", token)
}
return nil, fmt.Errorf("failed to get info for server %q: %w", token, err)
Defensive patterns

Strategy: validation

Validate before calling

id, err := strconv.ParseInt(strings.TrimPrefix(token, "hcloud://"), 10, 64)
if err != nil {
    return fmt.Errorf("invalid hetzner server ID in token: %w", err)
}
srv, _, err := client.Server.GetByID(ctx, id)
if err != nil {
    return fmt.Errorf("hetzner API error for server %d (check HCLOUD_TOKEN/connectivity): %w", id, err)
}
if srv == nil {
    return fmt.Errorf("server %d not found in this project; re-register the node", id)
}

Type guard

func serverFound(s *hcloud.Server) bool { return s != nil && s.ID != 0 }

Try / catch

if err != nil {
    var he *hcloud.Error
    if errors.As(err, &he) && he.Code == hcloud.ErrorCodeNotFound {
        // stale token: re-issue, do not retry
    } else if errors.As(err, &he) && he.Code == hcloud.ErrorCodeRateLimitExceeded {
        // transient: retry with backoff
    }
}

Prevention

When it happens

Trigger: A node presents a bootstrap token whose server ID does not exist in the Hetzner project (deleted/rebuilt server, wrong project), or the HCLOUD_TOKEN used by the verifier is invalid/insufficiently scoped, or the Hetzner API is unreachable/rate-limited so GetByID errors.

Common situations: Server was deleted and recreated so the ID in the token is stale; token copied from a different Hetzner project; HCLOUD_TOKEN on the kOps controller lacks the servers:read permission; network egress issues from the control plane to api.hetzner.cloud.

Related errors


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