{"record":{"id":"fbb715970336d3df","repo":"kubernetes/kops","slug":"invalid-gce-zone-v","errorCode":null,"errorMessage":"invalid GCE Zone: %v","messagePattern":"invalid GCE Zone: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gce/utils.go","lineNumber":172,"sourceCode":"// instance's \"ssh-keys\" metadata; the GCE guest agent creates this user on first boot. kOps\n// historically used fi.SecretNameSSHPrimary (\"admin\"), but on Ubuntu images the guest agent fails\n// to create that user because those images ship with an \"admin\" group\n// (https://github.com/kubernetes/kops/issues/16175), so the key was never installed. For Ubuntu\n// images we use the image's built-in \"ubuntu\" user instead. Other images keep \"admin\" so that SSH\n// access to existing non-Ubuntu clusters is unchanged.\nfunc SSHUsernameForImage(image string) string {\n\tname := LastComponent(image)\n\tif strings.HasPrefix(strings.ToLower(name), \"ubuntu\") {\n\t\treturn \"ubuntu\"\n\t}\n\treturn fi.SecretNameSSHPrimary\n}\n\n// ZoneToRegion maps a GCE zone name to a GCE region name, returning an error if it cannot be mapped\nfunc ZoneToRegion(zone string) (string, error) {\n\ttokens := strings.Split(zone, \"-\")\n\tif len(tokens) <= 2 {\n\t\treturn \"\", fmt.Errorf(\"invalid GCE Zone: %v\", zone)\n\t}\n\tregion := tokens[0] + \"-\" + tokens[1]\n\treturn region, nil\n}\n","sourceCodeStart":154,"sourceCodeEnd":177,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gce/utils.go#L154-L177","documentation":"ZoneToRegion maps a GCE zone (e.g. us-central1-a) to its region (us-central1) by splitting on '-' and keeping the first two tokens. The guard requires MORE than 2 tokens (len(tokens) <= 2 errors), so valid zones like \"us-central1-a\" (3 tokens) pass, but any string with two or fewer dash-separated parts — including a region passed by mistake — is rejected.","triggerScenarios":"Calling ZoneToRegion with an empty string, a bare region like \"us-central1\", or any malformed zone lacking a final dash component.","commonSituations":"Config supplying a region where a zone is expected; empty zone from unset environment/flags; truncated zone strings from parsing mistakes; typos like \"uscentral1a\".","solutions":["Pass a full zone with the -x suffix, e.g. \"us-central1-a\" not \"us-central1\"","Fix the config/flag/env that produced the empty or malformed zone value","Trim whitespace and validate the zone format before calling","Use `gcloud compute zones list` to confirm the exact zone name"],"exampleFix":"// before\nregion, err := ZoneToRegion(\"us-central1\") // invalid GCE Zone: us-central1\n// after\nregion, err := ZoneToRegion(\"us-central1-a\") // \"us-central1\", nil","handlingStrategy":"validation","validationCode":"func validateGCEZone(zone string) error {\n    tokens := strings.Split(zone, \"-\")\n    if len(tokens) <= 2 {\n        return fmt.Errorf(\"invalid GCE Zone %q: expected format like us-central1-a\", zone)\n    }\n    return nil\n}\n// call validateGCEZone(cfg.Zone) before ZoneToRegion","typeGuard":null,"tryCatchPattern":"region, err := ZoneToRegion(zone)\nif err != nil {\n    return fmt.Errorf(\"config.zone must be a full zone (e.g. us-central1-a), got %q: %w\", zone, err)\n}","preventionTips":["Distinguish zone vs region fields clearly in configs and flags","Never pass a region where ZoneToRegion expects a zone","Trim and validate zone input early at config load time","Verify zone names against `gcloud compute zones list`"],"tags":["gce","zone","region","validation","config"],"backgroundTag":"invalid-gce-zone","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"}