kubernetes/kops · error
created ServiceAccount did not have expected email; got %q;
Error message
created ServiceAccount did not have expected email; got %q; want %q
What it means
Immediately after creating a service account, RenderGCE verifies that GCP returned the exact email kOps requested. GCP computes the email from the accountId plus project, so a mismatch indicates the API created something unexpected (or a client/API quirk). This is a defensive consistency check, not a common runtime condition.
Source
Thrown at upup/pkg/fi/cloudup/gcetasks/serviceaccount.go:139
fqn := "projects/" + projectID + "/serviceAccounts/" + email
if a == nil {
klog.V(2).Infof("Creating ServiceAccount %q", fqn)
sa := &iam.CreateServiceAccountRequest{
AccountId: accountID,
ServiceAccount: &iam.ServiceAccount{
Description: fi.ValueOf(e.Description),
DisplayName: fi.ValueOf(e.DisplayName),
},
}
created, err := cloud.IAM().ServiceAccounts().Create(ctx, "projects/"+projectID, sa)
if err != nil {
return fmt.Errorf("error creating ServiceAccount %q: %w", fqn, err)
}
if created.Email != email {
return fmt.Errorf("created ServiceAccount did not have expected email; got %q; want %q", created.Email, email)
}
} else {
if changes.Description != nil || changes.DisplayName != nil {
sa := &iam.ServiceAccount{
Email: email,
Description: fi.ValueOf(e.Description),
DisplayName: fi.ValueOf(e.DisplayName),
}
_, err := cloud.IAM().ServiceAccounts().Update(ctx, fqn, sa)
if err != nil {
return fmt.Errorf("error creating ServiceAccount %q: %w", fqn, err)
}
changes.Description = nil
changes.DisplayName = nil
}
View on GitHub (pinned to 4c8573c808)
Solutions
- Compare got/want emails in the message and correct the Email field in the cluster spec to the exact canonical form (all lowercase).
- Verify with `gcloud iam service-accounts describe <created-email>` which account was actually created and update or delete it.
- Upgrade kOps and google.golang.org/api to current versions in case of a client-side email handling bug.
- If reproducible against a proxy/emulator, run against the real GCP endpoint.
Example fix
// before (mixed case)
Email: fi.String("Dev-Robot@example-project.iam.gserviceaccount.com")
// after
Email: fi.String("dev-robot@example-project.iam.gserviceaccount.com") Defensive patterns
Strategy: validation
Validate before calling
email := fi.ValueOf(e.Email)
if email != strings.ToLower(email) {
return fmt.Errorf("service account email %q must be lowercase", email)
} Type guard
func canonicalEmail(email string) bool {
return email == strings.ToLower(email) && strings.HasSuffix(email, ".iam.gserviceaccount.com")
} Try / catch
if err := kopsUpdate(); err != nil {
if strings.Contains(err.Error(), "did not have expected email") {
log.Print("delete the unexpected account and fix the Email field to canonical lowercase form")
}
return err
} Prevention
- Always store service account emails fully lowercase in cluster specs.
- After creation, verify with `gcloud iam service-accounts describe` that the email matches the spec.
- Don't run kOps through API-modifying proxies/emulators.
- Keep kOps and google.golang.org/api up to date.
When it happens
Trigger: created.Email != email after a successful Iam.ServiceAccounts().Create call in RenderGCE — e.g. GCP normalized the account ID differently or a proxy/mocks returned an inconsistent response.
Common situations: Case differences or unusual characters in the configured email that GCP normalized; stale/faulty API emulator or proxy; upstream google.golang.org/api behavior change; essentially only seen with a mistyped email containing mixed case.
Related errors
- ServiceAccount with email %q not found
- error creating ServiceAccount %q: %w
- cannot apply changes to ServiceAccount: %v
- error listing ServiceAccounts %w
- Invalid service account email '%s'
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/7d80bda119ffe27f.
Report an issue: GitHub.