{"record":{"id":"c7609f4606f289ed","repo":"kubernetes/kops","slug":"gcpprojectid-is-required","errorCode":null,"errorMessage":"gcpProjectID is required","messagePattern":"gcpProjectID is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go","lineNumber":115,"sourceCode":"\n\t// Guard against replay attacks\n\tif tokenData.Audience != gcetpm.AudienceNodeAuthentication {\n\t\treturn nil, fmt.Errorf(\"incorrect Audience\")\n\t}\n\ttimeSkew := math.Abs(time.Since(time.Unix(tokenData.Timestamp, 0)).Seconds())\n\tif timeSkew > float64(v.opt.MaxTimeSkew) {\n\t\treturn nil, fmt.Errorf(\"incorrect Timestamp %v\", tokenData.Timestamp)\n\t}\n\n\t// Verify the token has signed the body content.\n\trequestHash := sha256.Sum256(body)\n\tif !bytes.Equal(requestHash[:], tokenData.RequestHash) {\n\t\treturn nil, fmt.Errorf(\"incorrect RequestHash\")\n\t}\n\n\t// Some basic validation to avoid requesting invalid instances.\n\tif tokenData.GCPProjectID == \"\" {\n\t\treturn nil, fmt.Errorf(\"gcpProjectID is required\")\n\t}\n\tif tokenData.Zone == \"\" {\n\t\treturn nil, fmt.Errorf(\"zone is required\")\n\t}\n\tif tokenData.Instance == \"\" {\n\t\treturn nil, fmt.Errorf(\"instance is required\")\n\t}\n\n\t// Verify node is in our cluster\n\tif tokenData.GCPProjectID != v.opt.ProjectID {\n\t\treturn nil, fmt.Errorf(\"projectID does not match expected: got %q, want %q\", tokenData.GCPProjectID, v.opt.ProjectID)\n\t}\n\n\tinstance, err := v.computeClient.Instances.Get(tokenData.GCPProjectID, tokenData.Zone, tokenData.Instance).Context(ctx).Do()\n\tif err != nil {\n\t\tif isNotFound(err) {\n\t\t\treturn nil, fmt.Errorf(\"unable to find instance in compute API: %w\", err)\n\t\t}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go#L97-L133","documentation":"The signed token must identify the GCP project of the requesting instance so the verifier can look it up and validate it belongs to the cluster. An empty GCPProjectID in the token payload fails this basic validation.","triggerScenarios":"VerifyToken receives a token whose tokenData.GCPProjectID field is the empty string.","commonSituations":"A token producer that omits the project claim when minting the token, a client built against a different/older token schema that doesn't populate GCPProjectID, or manual/crafted token generation for testing.","solutions":["Fix the client to include the GCP project ID (e.g. from instance metadata `project/project-id`) when constructing the token.","Verify client and server share the same token struct/schema and JSON field names.","Check the token producer version matches what the verifier expects; upgrade the node component if the claim is missing due to a version mismatch."],"exampleFix":"// before\ntokenData := gcetpm.TokenData{Zone: zone, Instance: instance}\n// after\ntokenData := gcetpm.TokenData{GCPProjectID: projectID, Zone: zone, Instance: instance}","handlingStrategy":"validation","validationCode":"if tokenData.GCPProjectID == \"\" {\n\treturn fmt.Errorf(\"token missing GCPProjectID; client must set it from instance metadata\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Read project from GCE metadata (project/project-id) when minting","Keep client token schema in sync with the verifier","Add client-side pre-send validation of all required claims"],"tags":["gcp","tpm","validation","missing-field"],"backgroundTag":"missing-required-argument","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"}