{"record":{"id":"237eff7173700eed","repo":"kubernetes/kops","slug":"failed-to-get-info-for-server-q-w-237eff","errorCode":null,"errorMessage":"failed to get info for server %q: %w","messagePattern":"failed to get info for server %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/hetzner/verifier.go","lineNumber":75,"sourceCode":"\treturn &hetznerVerifier{\n\t\topt:    *opt,\n\t\tclient: hcloudClient,\n\t}, nil\n}\n\nfunc (h hetznerVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {\n\tif !strings.HasPrefix(token, hetznermetadata.HetznerAuthenticationTokenPrefix) {\n\t\treturn nil, bootstrap.ErrNotThisVerifier\n\t}\n\ttoken = strings.TrimPrefix(token, hetznermetadata.HetznerAuthenticationTokenPrefix)\n\n\tserverID, err := strconv.ParseInt(token, 10, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert server ID %q to int: %w\", token, err)\n\t}\n\tserver, _, err := h.client.Server.GetByID(ctx, serverID)\n\tif err != nil || server == nil {\n\t\treturn nil, fmt.Errorf(\"failed to get info for server %q: %w\", token, err)\n\t}\n\n\tvar addrs []string\n\tvar challengeEndpoints []string\n\tif server.PublicNet.IPv4.IP != nil {\n\t\t// Don't challenge over the public network\n\t\taddrs = append(addrs, server.PublicNet.IPv4.IP.String())\n\t}\n\tfor _, network := range server.PrivateNet {\n\t\tif network.IP != nil {\n\t\t\taddrs = append(addrs, network.IP.String())\n\t\t\tchallengeEndpoints = append(challengeEndpoints, net.JoinHostPort(network.IP.String(), strconv.Itoa(wellknownports.NodeupChallenge)))\n\t\t}\n\t}\n\n\tif len(challengeEndpoints) == 0 {\n\t\treturn nil, fmt.Errorf(\"cannot determine challenge endpoint for server %d\", serverID)\n\t}","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/hetzner/verifier.go#L57-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","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)."],"exampleFix":"// debugging the wrapped cause\nif _, _, err := client.Server.GetByID(ctx, serverID); err != nil {\n    if hcloud.IsError(err, hcloud.ErrorCodeNotFound) {\n        // token references a server that no longer exists; re-issue node bootstrap token\n    }\n}\n// before: opaque failure\nreturn nil, fmt.Errorf(\"failed to get info for server %q: %w\", token, err)\n// after: distinguish not-found from transient API errors\nif err != nil && hcloud.IsError(err, hcloud.ErrorCodeNotFound) {\n    return nil, fmt.Errorf(\"server %q not found in this Hetzner project; re-register the node\", token)\n}\nreturn nil, fmt.Errorf(\"failed to get info for server %q: %w\", token, err)","handlingStrategy":"validation","validationCode":"id, err := strconv.ParseInt(strings.TrimPrefix(token, \"hcloud://\"), 10, 64)\nif err != nil {\n    return fmt.Errorf(\"invalid hetzner server ID in token: %w\", err)\n}\nsrv, _, err := client.Server.GetByID(ctx, id)\nif err != nil {\n    return fmt.Errorf(\"hetzner API error for server %d (check HCLOUD_TOKEN/connectivity): %w\", id, err)\n}\nif srv == nil {\n    return fmt.Errorf(\"server %d not found in this project; re-register the node\", id)\n}","typeGuard":"func serverFound(s *hcloud.Server) bool { return s != nil && s.ID != 0 }","tryCatchPattern":"if err != nil {\n    var he *hcloud.Error\n    if errors.As(err, &he) && he.Code == hcloud.ErrorCodeNotFound {\n        // stale token: re-issue, do not retry\n    } else if errors.As(err, &he) && he.Code == hcloud.ErrorCodeRateLimitExceeded {\n        // transient: retry with backoff\n    }\n}","preventionTips":["Keep HCLOUD_TOKEN scoped to the project that owns the cluster's servers and rotate it before expiry","Re-issue node bootstrap tokens whenever a server is deleted and recreated (IDs change)","Monitor for hcloud rate-limit (429) errors from the verifier and back off","Check server existence with hcloud CLI before debugging the verifier"],"tags":["hetzner","bootstrap","api","authentication"],"backgroundTag":"cloud-resource-not-found","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}