{"record":{"id":"7282a454a9ce5e91","repo":"kubernetes/kops","slug":"error-parsing-akamai-linode-s-id-q-w","errorCode":null,"errorMessage":"error parsing Akamai (Linode) %s ID %q: %w","messagePattern":"error parsing Akamai \\(Linode\\) (.+?) ID %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/linode/resources.go","lineNumber":46,"sourceCode":"\t\"k8s.io/kops/upup/pkg/fi\"\n\tcloudlinode \"k8s.io/kops/upup/pkg/fi/cloudup/linode\"\n)\n\ntype listFn func(fi.Cloud, resources.ClusterInfo) ([]*resources.Resource, error)\n\nconst (\n\tresourceTypeVPC      = \"vpc\"\n\tresourceTypeSubnet   = \"subnet\"\n\tresourceTypeSSHKey   = \"ssh-key\"\n\tresourceTypeInstance = \"instance\"\n\tresourceTypeVolume   = \"volume\"\n)\n\n// parseTrackerIntID parses the tracker's string ID into an integer, which is used for Akamai (Linode) resource IDs.\nfunc parseTrackerIntID(tracker *resources.Resource) (int, error) {\n\tid, err := strconv.Atoi(tracker.ID)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"error parsing Akamai (Linode) %s ID %q: %w\", tracker.Type, tracker.ID, err)\n\t}\n\treturn id, nil\n}\n\n// ListResources collects Akamai (Linode) cloud resources owned by the cluster.\nfunc ListResources(cloud cloudlinode.LinodeCloud, clusterInfo resources.ClusterInfo) (map[string]*resources.Resource, error) {\n\tresourceTrackers := make(map[string]*resources.Resource)\n\n\tlistFunctions := []listFn{\n\t\tlistVPCs,\n\t\tlistSubnets,\n\t\tlistInstances,\n\t\tlistVolumes,\n\t\tlistSSHKeys,\n\t}\n\n\tfor _, fn := range listFunctions {\n\t\ttrackers, err := fn(cloud, clusterInfo)","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/linode/resources.go#L28-L64","documentation":"parseTrackerIntID in kOps' Akamai (Linode) resource listing converts the tracker's string ID to an int (Linode resource IDs are numeric). If strconv.Atoi fails, this error wraps the parse failure, naming the resource type and the offending ID string. It propagates out of every Linode delete function (deleteSSHKey, deleteVPC, deleteSubnet, deleteInstance, deleteVolume).","triggerScenarios":"tracker.ID is not a plain decimal integer: empty string, whitespace, a Linode label instead of an ID, or a corrupted/edited kOps state store entry.","commonSituations":"Manually edited cluster state in the kOps state store; a resource tracker populated with a label like \"my-ssh-key\" instead of the numeric Linode ID; older kOps version wrote a different ID format than the current code expects.","solutions":["Inspect the tracker ID in the error message and in the kOps state store; replace any non-numeric ID with the correct numeric Linode ID.","Find the real ID with `linode-cli sshkeys list` / `linode-cli vpcs list` etc., and correct the state entry.","If the resource no longer exists, remove the stale tracker from the state store so kOps stops trying to delete it.","Upgrade/downgrade kOps if a version change changed the ID format written to state."],"exampleFix":"// before: tracker.ID is a label\nid, err := strconv.Atoi(tracker.ID) // \"my-cluster-vpc\" -> error\n// after: validate before use\nid, err := strconv.Atoi(strings.TrimSpace(tracker.ID))\nif err != nil {\n    return 0, fmt.Errorf(\"error parsing Akamai (Linode) %s ID %q: %w\", tracker.Type, tracker.ID, err)\n}\n// caller-side: only create trackers with fmt.Sprintf(\"%d\", numericID)","handlingStrategy":"validation","validationCode":"func validLinodeID(id string) bool {\n    _, err := strconv.Atoi(strings.TrimSpace(id))\n    return err == nil\n}\n// call before invoking any delete: if !validLinodeID(tracker.ID) { fix state store entry first }","typeGuard":"func isIDParseError(err error) bool {\n    var numErr *strconv.NumError\n    return errors.As(err, &numErr)\n}","tryCatchPattern":"id, err := parseTrackerIntID(tracker)\nif err != nil {\n    var numErr *strconv.NumError\n    if errors.As(err, &numErr) {\n        log.Printf(\"skipping malformed tracker ID %q for %s; clean up manually\", tracker.ID, tracker.Type)\n        return nil\n    }\n    return err\n}","preventionTips":["Never hand-edit resource IDs in the kOps state store; regenerate them via kOps tooling.","Only write trackers with numeric IDs (fmt.Sprintf(\"%d\", linodeID)).","After a kOps upgrade, run `kops get cluster` to validate state before deleting.","Trim whitespace/labels from IDs at resource-registration time."],"tags":["linode","akamai","id-parsing","state-store"],"backgroundTag":"strconv-atoi-invalid-id","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"}