{"record":{"id":"513c98959c2fe033","repo":"kubernetes/kops","slug":"error-creating-akamai-linode-volume-q-w","errorCode":null,"errorMessage":"error creating Akamai (Linode) volume %q: %w","messagePattern":"error creating Akamai \\(Linode\\) volume %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/linodetasks/volume.go","lineNumber":147,"sourceCode":"\t\t\treturn nil\n\t\t}\n\t\tif err := t.Cloud.Client().ResizeVolume(context.Background(), fi.ValueOf(actual.ID), linodego.VolumeResizeOptions{Size: fi.ValueOf(expected.SizeGB)}); err != nil {\n\t\t\treturn fmt.Errorf(\"error resizing Akamai (Linode) volume %q: %w\", fi.ValueOf(actual.Name), err)\n\t\t}\n\t\tklog.V(2).Infof(\"Resized Akamai (Linode) volume %q (id=%d) to %d GB\", fi.ValueOf(actual.Name), fi.ValueOf(actual.ID), fi.ValueOf(expected.SizeGB))\n\t\treturn nil\n\t}\n\n\tname := fi.ValueOf(expected.Name)\n\tlabel := truncate.TruncateString(linode.NormalizeLinodeLabel(name), truncate.TruncateStringOptions{MaxLength: 32})\n\tcreated, err := t.Cloud.Client().CreateVolume(context.Background(), linodego.VolumeCreateOptions{\n\t\tLabel:  label,\n\t\tRegion: fi.ValueOf(expected.Region),\n\t\tSize:   fi.ValueOf(expected.SizeGB),\n\t\tTags:   expected.Tags,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating Akamai (Linode) volume %q: %w\", name, err)\n\t}\n\n\texpected.ID = new(created.ID)\n\tklog.V(2).Infof(\"Created Akamai (Linode) volume %q (id=%d)\", created.Label, created.ID)\n\n\treturn nil\n}\n","sourceCodeStart":129,"sourceCodeEnd":155,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/linodetasks/volume.go#L129-L155","documentation":"This error wraps a failure from the Linode API CreateVolume call when RenderLinode needs to provision a new block-storage volume that Find() could not locate. The task's own pre-checks (Name/Region/SizeGB required, min 10 GB) have already passed, so the failure comes from the Linode API itself - quota, invalid region, label conflict, or transient error - and is preserved via %w.","triggerScenarios":"Volume does not exist under the truncated/normalized label, so CreateVolume is invoked and the API rejects it: account volume limit reached, region has no capacity, region string invalid, label already taken by another volume, invalid token/scopes, or a 500 from the API.","commonSituations":"New cluster bring-up in a region with volume quota exhausted; reusing a label that exists under a different name that escaped the label-based Find (name longer than 32 chars truncates differently); typo in region in the cluster spec; expired or under-scoped API token.","solutions":["Check the wrapped linodego error for quota/limit messages and delete unused volumes or request a quota increase","Verify the Region in the cluster spec is a valid Linode region with volume availability","Ensure the volume Name is unique and <= 32 characters after NormalizeLinodeLabel/TruncateString so Find() can locate an existing volume instead of creating a duplicate","Confirm the API token is valid and has volumes:read_write scope","Retry on transient 5xx errors; kops will re-run the task"],"exampleFix":"// before: ambiguous long name silently truncated, Find misses existing volume\nname: \"my-very-long-volume-name-that-exceeds-32-characters\"\n// after: short unique name that round-trips through NormalizeLinodeLabel\nname: \"my-cluster-data-vol1\"","handlingStrategy":"validation","validationCode":"func validateVolumeCreate(name, region string, sizeGB int) error {\n    if len(name) == 0 || len(name) > 32 {\n        return fmt.Errorf(\"volume name %q must be 1-32 chars to survive label truncation\", name)\n    }\n    if sizeGB < 10 || sizeGB > 10240 {\n        return fmt.Errorf(\"SizeGB %d out of allowed range 10-10240\", sizeGB)\n    }\n    if region == \"\" {\n        return fmt.Errorf(\"region is required\")\n    }\n    return nil\n}","typeGuard":"func isQuotaError(err error) bool {\n    var apiErr *linodego.Error\n    return errors.As(err, &apiErr) && (apiErr.Code == 400 || apiErr.Code == 452) &&\n        strings.Contains(strings.ToLower(apiErr.Message), \"limit\")\n}","tryCatchPattern":"if err := run(); err != nil {\n    var apiErr *linodego.Error\n    if errors.As(err, &apiErr) {\n        switch apiErr.Code {\n        case 401, 403:\n            return fmt.Errorf(\"check LINODE_TOKEN scopes: %w\", err)\n        case 429:\n            return fmt.Errorf(\"rate limited, retry later: %w\", err)\n        }\n    }\n    return err\n}","preventionTips":["Keep volume names short (<=32 chars) and unique per account/region","Verify the region string against `linode-cli regions list` before bring-up","Monitor account volume count/size quota","Ensure API token has volumes:read_write scope","After a failed run, check for partially created volumes to avoid duplicates"],"tags":["linode","storage","create","api-error","kops"],"backgroundTag":"linode-volume-create-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}