kubernetes/kops · error

ServiceAccount with email %q not found

Error message

ServiceAccount with email %q not found

What it means

RenderGCE throws this when a GCE ServiceAccount task is marked Shared (i.e. kOps does not own or create the service account) but the Find phase returned no existing service account for the configured email. For shared accounts kOps must reuse a pre-existing account; creating it would be wrong, so the apply aborts. It means the cluster spec references a service account that does not exist in the target GCP project.

Source

Thrown at upup/pkg/fi/cloudup/gcetasks/serviceaccount.go:112

	return fi.CloudupDefaultDeltaRunMethod(e, c)
}

func (_ *ServiceAccount) CheckChanges(a, e, changes *ServiceAccount) error {
	return nil
}

func (_ *ServiceAccount) RenderGCE(t *gce.GCEAPITarget, a, e, changes *ServiceAccount) error {
	ctx := context.TODO()

	cloud := t.Cloud

	email := fi.ValueOf(e.Email)

	shared := fi.ValueOf(e.Shared)
	if shared {
		// Verify the service account was found
		if a == nil {
			return fmt.Errorf("ServiceAccount with email %q not found", email)
		}
	}

	accountID, projectID, err := gce.SplitServiceAccountEmail(email)
	if err != nil {
		return err
	}

	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),

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the service account exists: `gcloud iam service-accounts list --project=<project>` and compare with the Email in the cluster spec.
  2. Fix a typo or wrong project ID in the service account email in the cluster spec, then re-run update.
  3. Recreate the deleted service account (or change Shared to false so kOps creates and manages it).
  4. Ensure kOps credentials target the project where the account actually lives (check GOOGLE_APPLICATION_CREDENTIALS / project flag).

Example fix

// cluster spec, before (account doesn't exist in project)
sharedServiceAccount: shared@example-project.iam.gserviceaccount.com
// after
dev-robot@example-project.iam.gserviceaccount.com  // correct, existing account
Defensive patterns

Strategy: validation

Validate before calling

sa := fi.ValueOf(e.Email)
if fi.ValueOf(e.Shared) {
    if _, err := exec.Command("gcloud", "iam", "service-accounts", "describe", sa, "--format=value(email)").Output(); err != nil {
        return fmt.Errorf("shared ServiceAccount %q does not exist in target project", sa)
    }
}

Type guard

func sharedAccountFound(a *ServiceAccount, shared bool) bool { return !shared || a != nil }

Try / catch

if err := kopsUpdate(); err != nil {
    if strings.Contains(err.Error(), "ServiceAccount with email") {
        log.Printf("shared SA missing; create it with: gcloud iam service-accounts create <id> --project=<proj>")
    }
    return err
}

Prevention

When it happens

Trigger: Running `kops update cluster` against GCE where a ServiceAccount task has Shared=true and the email does not resolve to an existing IAM service account (Find returned nil, so `a == nil` in RenderGCE).

Common situations: Typo in the service account email in the cluster spec; the account was deleted in GCP after the cluster was created; cluster pointed at the wrong --project or wrong project inside the email (emails embed project ID via gce.SplitServiceAccountEmail); the account lives in a different project than the one kOps is authenticated against.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/ee4ad53318368868. Report an issue: GitHub.