{"record":{"id":"4307890acfe8d64d","repo":"kubernetes/kops","slug":"failed-to-convert-provider-id-number-q-s","errorCode":null,"errorMessage":"failed to convert provider ID number %q: %s","messagePattern":"failed to convert provider ID number %q: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nodeidentity/do/identify.go","lineNumber":145,"sourceCode":"\t\treturn nil, fmt.Errorf(\"provider ID %q is missing prefix %q\", providerID, prefix)\n\t}\n\n\tinstanceID := strings.TrimPrefix(providerID, prefix)\n\tif instanceID == \"\" {\n\t\treturn nil, errors.New(\"provider ID number cannot be empty\")\n\t}\n\n\tif i.cacheEnabled {\n\t\tif obj, exists, err := i.cache.GetByKey(instanceID); err != nil {\n\t\t\tklog.Warningf(\"Nodeidentity info cache lookup failure: %v\", err)\n\t\t} else if exists {\n\t\t\treturn obj.(*nodeidentity.Info), nil\n\t\t}\n\t}\n\n\tdropletID, err := strconv.Atoi(instanceID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert provider ID number %q: %s\", instanceID, err)\n\t}\n\n\tdroplet, _, err := i.doClient.Droplets.Get(ctx, dropletID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to retrieve droplet %d: %w\", dropletID, err)\n\t}\n\tif droplet == nil {\n\t\treturn nil, fmt.Errorf(\"droplet %d not found\", dropletID)\n\t}\n\tif droplet.Status != \"active\" && droplet.Status != \"new\" {\n\t\treturn nil, fmt.Errorf(\"droplet %d has unexpected status %q\", dropletID, droplet.Status)\n\t}\n\n\tinfo := &nodeidentity.Info{\n\t\tInstanceID: instanceID,\n\t\tLabels:     labelsFromTags(droplet.Tags),\n\t}\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/nodeidentity/do/identify.go#L127-L163","documentation":"After stripping the 'digitalocean://' prefix, the remainder must be a numeric droplet ID. strconv.Atoi fails if it is non-numeric (or empty, though empty is caught earlier), producing this error with the offending value.","triggerScenarios":"providerID like 'digitalocean://abc' or 'digitalocean://droplet-123' passed to IdentifyNode — the instance portion contains non-digit characters.","commonSituations":"Custom tooling writing UUIDs or instance names instead of numeric droplet IDs into providerID; DO CCM version mismatch producing a different ID format; typos in manual cluster configuration.","solutions":["Ensure the part after 'digitalocean://' is the numeric droplet ID (digits only)","Look up the droplet's numeric ID in the DigitalOcean console or API (doctl compute droplet list) and fix the providerID","Check the DO cloud controller manager version — it should set numeric droplet IDs","Trim stray whitespace or URL fragments from the providerID value"],"exampleFix":"// before\n\"digitalocean://my-droplet-name\"\n// after\n\"digitalocean://3164444\"","handlingStrategy":"validation","validationCode":"id := strings.TrimPrefix(providerID, \"digitalocean://\")\nif n, err := strconv.Atoi(id); err != nil || n <= 0 {\n    return fmt.Errorf(\"droplet ID must be numeric, got %q\", id)\n}","typeGuard":"func isNumericDropletID(id string) bool {\n    n, err := strconv.Atoi(id)\n    return err == nil && n > 0\n}","tryCatchPattern":"info, err := IdentifyNode(ctx, providerID)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to convert provider ID number\") {\n        // surface a config error; fix providerID to a numeric droplet ID\n    }\n}","preventionTips":["Always store the numeric droplet ID (not name/UUID/slug) in providerID","Sanitize whitespace and fragments from IDs before parsing","Keep the DO CCM version aligned with kops expectations for ID format","Unit-test providerID parsing with real ID samples"],"tags":["digitalocean","provider-id","parsing","strconv"],"backgroundTag":"provider-id-not-numeric","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"}