{"record":{"id":"f4766800920a02b7","repo":"kubernetes/kops","slug":"failed-to-get-volumes-matching-label-selector-q","errorCode":null,"errorMessage":"failed to get volumes matching label selector %q: %w","messagePattern":"failed to get volumes matching label selector %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/hetzner/cloud.go","lineNumber":240,"sourceCode":"\t\treturn nil, fmt.Errorf(\"failed to get servers matching label selector %q: %w\", labelSelector, err)\n\t}\n\n\treturn matches, nil\n}\n\nfunc (c *hetznerCloudImplementation) GetVolumes(clusterName string) ([]*hcloud.Volume, error) {\n\tclient := c.VolumeClient()\n\n\tlabelSelector := TagKubernetesClusterName + \"=\" + clusterName\n\tlistOptions := hcloud.ListOpts{\n\t\tPerPage:       50,\n\t\tLabelSelector: labelSelector,\n\t}\n\tvolumeListOptions := hcloud.VolumeListOpts{ListOpts: listOptions}\n\n\tmatches, err := client.AllWithOpts(context.TODO(), volumeListOptions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get volumes matching label selector %q: %w\", labelSelector, err)\n\t}\n\n\treturn matches, nil\n}\n\nfunc (c *hetznerCloudImplementation) DNS() (dnsprovider.Interface, error) {\n\t// Hetzner LB has a stable internal IP and can use that instead of creating a record for api.internal.\n\treturn nil, nil\n}\n\nfunc (c *hetznerCloudImplementation) DeleteInstance(instance *cloudinstances.CloudInstance) error {\n\tserverID, err := strconv.ParseInt(instance.ID, 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to convert server ID %q to int: %w\", instance.ID, err)\n\t}\n\n\terr = deleteServer(c, serverID)\n","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/hetzner/cloud.go#L222-L258","documentation":"GetVolumes wraps errors from hcloud VolumeClient.AllWithOpts when listing volumes filtered by the cluster label selector. It signals that the Hetzner Cloud API volume-list request failed, with the underlying hcloud error preserved.","triggerScenarios":"Calling GetVolumes with invalid credentials, no network access to api.hetzner.cloud, API rate limiting, or a Hetzner-side error on the /volumes endpoint.","commonSituations":"kOps cluster validation/deletion on Hetzner when the token expired, when running behind a corporate proxy blocking Hetzner API, or during Hetzner API incidents.","solutions":["Validate HCLOUD_TOKEN is set, unexpired, and belongs to the cluster's project","Retry after backoff if rate-limited (429)","Verify outbound connectivity/proxy settings to api.hetzner.cloud","Inspect the wrapped cause for the specific hcloud error code"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if os.Getenv(\"HCLOUD_TOKEN\") == \"\" {\n\treturn fmt.Errorf(\"HCLOUD_TOKEN must be set before calling GetVolumes\")\n}","typeGuard":"var hcloudErr *hcloud.Error\nif errors.As(err, &hcloudErr) {\n\t// branch on hcloudErr.Code\n}","tryCatchPattern":"vols, err := cloud.GetVolumes(clusterName)\nif err != nil {\n\tvar hErr *hcloud.Error\n\tif errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeRateLimit {\n\t\ttime.Sleep(hErr.RateLimit.RetryAfter())\n\t\tvols, err = cloud.GetVolumes(clusterName)\n\t}\n}","preventionTips":["Verify token validity/scoping before cluster operations","Check proxy/firewall allows api.hetzner.cloud","Unwrap errors to log precise hcloud error codes","Add retry-on-429 logic around list operations"],"tags":["hetzner","api","volumes","network"],"backgroundTag":"hetzner-api-request-failed","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"}