{"record":{"id":"4706e9f51d564b3b","repo":"kubernetes/kops","slug":"failed-to-list-servers-w","errorCode":null,"errorMessage":"failed to list servers: %w","messagePattern":"failed to list servers: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/hetzner/resources.go","lineNumber":172,"sourceCode":"\t\t\tID:      strconv.FormatInt(loadBalancer.ID, 10),\n\t\t\tType:    resourceTypeLoadBalancer,\n\t\t\tDeleter: deleteLoadBalancer,\n\t\t\tObj:     loadBalancer,\n\t\t}\n\n\t\tresourceTrackers = append(resourceTrackers, resourceTracker)\n\t}\n\n\treturn resourceTrackers, nil\n}\n\nfunc listServers(cloud fi.Cloud, clusterName string) ([]*resources.Resource, error) {\n\tc := cloud.(hetzner.HetznerCloud)\n\tvar resourceTrackers []*resources.Resource\n\n\tservers, err := c.GetServers(clusterName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list servers: %w\", err)\n\t}\n\n\tfor _, server := range servers {\n\t\tresourceTracker := &resources.Resource{\n\t\t\tName:    server.Name,\n\t\t\tID:      strconv.FormatInt(server.ID, 10),\n\t\t\tType:    resourceTypeServer,\n\t\t\tDeleter: deleteServer,\n\t\t\tDumper:  dumpServer,\n\t\t\tObj:     server,\n\t\t}\n\n\t\tfor _, firewall := range server.PublicNet.Firewalls {\n\t\t\tresourceTracker.Blocks = append(resourceTracker.Blocks, fmt.Sprintf(\"%s:%d\", resourceTypeFirewall, firewall.Firewall.ID))\n\t\t}\n\n\t\tresourceTrackers = append(resourceTrackers, resourceTracker)\n\t}","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/hetzner/resources.go#L154-L190","documentation":"Returned by listServers when GetServers(clusterName) fails enumerating Hetzner servers during cluster resource discovery (delete path). Server listing is the core of discovery, so failure aborts the operation. The underlying hcloud SDK/API error is preserved via %w wrapping.","triggerScenarios":"Hetzner servers.list API call fails: invalid token, rate limiting, API 5xx outage, request timeout, or network egress blocked to api.hetzner.cloud.","commonSituations":"Automated cleanup scripts hammering the API trigger 429 rate_limit_exceeded; HCLOUD_TOKEN reset/revoked; Hetzner incident; running kops from a machine without outbound HTTPS access.","solutions":["Confirm API access: curl -H \"Authorization: Bearer $HCLOUD_TOKEN\" https://api.hetzner.cloud/v1/servers.","On rate limit errors, honor X-Ratelimit-Reset and space out API calls before re-running.","Replace an expired/revoked token with a new one from the Hetzner Cloud Console.","Retry after checking status.hetzner.com if the wrapped error is a 5xx."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"resp, err := hc.Get(\"https://api.hetzner.cloud/v1/servers\")\nif err != nil || resp.StatusCode != 200 {\n    return fmt.Errorf(\"servers API precheck failed: token/network problem\")\n}","typeGuard":"var hErr hcloud.Error\nif errors.As(err, &hErr) && (hErr.Code == hcloud.ErrorCodeUnauthorized || hErr.Code == hcloud.ErrorCodeRateLimitExceeded) {\n    // handle auth vs throttling differently\n}","tryCatchPattern":"servers, err := c.GetServers(clusterName)\nvar hErr hcloud.Error\nif errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeRateLimitExceeded {\n    time.Sleep(time.Until(ratelimitReset))\n    servers, err = c.GetServers(clusterName)\n}","preventionTips":["Avoid parallel kops cleanup jobs sharing one token.","Refresh HCLOUD_TOKEN after team rotations.","Confirm outbound HTTPS to api.hetzner.cloud from CI runners.","Retry 5xx with exponential backoff; abort-fast on 401."],"tags":["hetzner","server","api","cloud-provider"],"backgroundTag":"cloud-api-auth-failure","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"}