kubernetes/kops · error
projectID does not match expected: got %q, want %q
Error message
projectID does not match expected: got %q, want %q
What it means
The verifier enforces that the token's GCPProjectID equals the project it was configured to serve (v.opt.ProjectID). This stops instances from other projects — even ones with valid tokens — from authenticating into this cluster.
Source
Thrown at upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go:126
requestHash := sha256.Sum256(body)
if !bytes.Equal(requestHash[:], tokenData.RequestHash) {
return nil, fmt.Errorf("incorrect RequestHash")
}
// Some basic validation to avoid requesting invalid instances.
if tokenData.GCPProjectID == "" {
return nil, fmt.Errorf("gcpProjectID is required")
}
if tokenData.Zone == "" {
return nil, fmt.Errorf("zone is required")
}
if tokenData.Instance == "" {
return nil, fmt.Errorf("instance is required")
}
// Verify node is in our cluster
if tokenData.GCPProjectID != v.opt.ProjectID {
return nil, fmt.Errorf("projectID does not match expected: got %q, want %q", tokenData.GCPProjectID, v.opt.ProjectID)
}
instance, err := v.computeClient.Instances.Get(tokenData.GCPProjectID, tokenData.Zone, tokenData.Instance).Context(ctx).Do()
if err != nil {
if isNotFound(err) {
return nil, fmt.Errorf("unable to find instance in compute API: %w", err)
}
return nil, fmt.Errorf("error fetching instance from compute API: %w", err)
}
if !strings.HasPrefix(lastComponent(instance.Zone), v.opt.Region+"-") {
return nil, fmt.Errorf("instance was in zone %q, expected region %q", instance.Zone, v.opt.Region)
}
clusterName := ""
instanceGroupName := ""
for _, item := range instance.Metadata.Items {
switch item.Key {View on GitHub (pinned to 4c8573c808)
Solutions
- Correct v.opt.ProjectID (verifier configuration) to the project the nodes actually run in.
- Fix the node/cluster configuration so instances are created in the expected project.
- If the cluster intentionally moved projects, update the verifier's project and restart it.
Example fix
// before v.opt.ProjectID = "old-project" // after v.opt.ProjectID = "my-cluster-project"
Defensive patterns
Strategy: validation
Validate before calling
if tokenData.GCPProjectID != expectedProjectID {
return fmt.Errorf("token from project %q but verifier serves %q", tokenData.GCPProjectID, expectedProjectID)
} Prevention
- Double-check the verifier's ProjectID option at deploy time
- Keep cluster project and verifier config in the same source of truth
- Use one verifier per project in multi-project setups
When it happens
Trigger: tokenData.GCPProjectID (from the signed token) differs from v.opt.ProjectID in the verifier's options.
Common situations: Verifier deployed with the wrong --project / ProjectID option, cluster moved to a different GCP project without updating the verifier config, a multi-project setup sending nodes to the wrong verifier, or a typo in the project ID configuration.
Related errors
- instance was in zone %q, expected region %q
- unhandled LoadBalancer type %q
- unable to determine zones in region %q
- found multiple instance groups matching MIG %q
- failed to get GCE RSA attestation key from TPM: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/e0140f2385932d93.
Report an issue: GitHub.