{"record":{"id":"05bf547515ce9cf4","repo":"kubernetes/kops","slug":"failed-to-list-volumes-w","errorCode":null,"errorMessage":"failed to list volumes: %w","messagePattern":"failed to list volumes: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/hetzner/resources.go","lineNumber":201,"sourceCode":"\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}\n\n\treturn resourceTrackers, nil\n}\n\nfunc listVolumes(cloud fi.Cloud, clusterName string) ([]*resources.Resource, error) {\n\tc := cloud.(hetzner.HetznerCloud)\n\tvar resourceTrackers []*resources.Resource\n\n\tvolumes, err := c.GetVolumes(clusterName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list volumes: %w\", err)\n\t}\n\n\tfor _, volume := range volumes {\n\t\tresourceTracker := &resources.Resource{\n\t\t\tName:    volume.Name,\n\t\t\tID:      strconv.FormatInt(volume.ID, 10),\n\t\t\tType:    resourceTypeVolume,\n\t\t\tDeleter: deleteVolume,\n\t\t\tObj:     volume,\n\t\t}\n\n\t\tif volume.Server != nil {\n\t\t\tresourceTracker.Blocked = append(resourceTracker.Blocked, fmt.Sprintf(\"%s:%d\", resourceTypeServer, volume.Server.ID))\n\t\t}\n\n\t\tresourceTrackers = append(resourceTrackers, resourceTracker)\n\t}\n","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/hetzner/resources.go#L183-L219","documentation":"Returned by listVolumes when GetVolumes(clusterName) fails during Hetzner cluster discovery. kops lists volumes to identify cluster-attached volumes for deletion; an API failure aborts discovery. The real cause (auth, quota, outage) is wrapped with %w inside this message.","triggerScenarios":"Hetzner volumes.list API call fails: authentication error, rate limit, API outage, or network failure to api.hetzner.cloud.","commonSituations":"Same project-token mismatch as other Hetzner lists; token under-scoped (no volumes read); bursts of API calls in CI cleanup pipelines hitting rate limits; Hetzner maintenance.","solutions":["Check credentials with curl -H \"Authorization: Bearer $HCLOUD_TOKEN\" https://api.hetzner.cloud/v1/volumes.","For 429 responses, wait for the rate-limit window and retry.","Confirm the token's project actually hosts the cluster's volumes.","Retry after confirming no Hetzner outage on status.hetzner.com."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"resp, err := hc.Get(\"https://api.hetzner.cloud/v1/volumes\")\nif err != nil || resp.StatusCode != 200 {\n    return fmt.Errorf(\"volumes API precheck failed; verify HCLOUD_TOKEN\")\n}","typeGuard":"var hErr hcloud.Error\nif errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeUnauthorized {\n    // token problem, do not retry\n}","tryCatchPattern":"volumes, err := c.GetVolumes(clusterName)\nif err != nil {\n    var hErr hcloud.Error\n    if errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeRateLimitExceeded {\n        time.Sleep(backoff)\n        volumes, err = c.GetVolumes(clusterName)\n    }\n}","preventionTips":["Verify the token has volumes read permission in the correct project.","Serialize API-heavy cleanup pipelines to avoid 429s.","Check Hetzner status before large delete operations.","Cache discovery results to minimize repeated list calls."],"tags":["hetzner","volume","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"}