kubernetes/kops · error

error listing ServiceAccount %q: %w

Error message

error listing ServiceAccount %q: %w

What it means

Returned by the GCE ServiceAccount task's Find when IAM().ServiceAccounts().Get() fails with an error that is not NotFound. kOps uses this call to look up the managed service account by fully-qualified name (projects/<project>/serviceAccounts/<email>) to compute the diff; since the error is not 'not found', kOps cannot determine the actual state and fails the task. The wrapped error holds the real cause.

Source

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

	email := fi.ValueOf(e.Email)

	if email == "default" {
		// Special case - the default serviceaccount always exists
		return e, nil
	}

	_, projectID, err := gce.SplitServiceAccountEmail(email)
	if err != nil {
		return nil, err
	}
	fqn := "projects/" + projectID + "/serviceAccounts/" + email
	sa, err := cloud.IAM().ServiceAccounts().Get(ctx, fqn)
	if err != nil {
		if gce.IsNotFound(err) {
			return nil, nil
		}
		return nil, fmt.Errorf("error listing ServiceAccount %q: %w", fqn, err)
	}

	// Check the email actually matches what we expect
	if email != sa.Email {
		return nil, fmt.Errorf("found ServiceAccount but email did not match expected; got %q; want %q", sa.Email, email)
	}

	actual := &ServiceAccount{}
	actual.DisplayName = &sa.DisplayName
	actual.Description = &sa.Description
	actual.Email = &sa.Email

	// Prevent spurious changes
	actual.Lifecycle = e.Lifecycle
	actual.Name = e.Name
	actual.Shared = e.Shared

	return actual, nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the wrapped error: if permissionDenied, grant the caller roles/iam.serviceAccountViewer (or roles/iam.serviceAccountUser)
  2. Verify the IAM API (iam.googleapis.com) is enabled in the project
  3. Confirm the service account email in the cluster spec is correct and the project ID matches (fqn is projects/<projectID>/serviceAccounts/<email>)
  4. If transient (5xx/rate limit), retry `kops update cluster`
  5. If the service account should not exist anymore, reconcile the cluster spec or recreate it via kOps

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate IAM API access and service account existence before apply
desired := "projects/" + projectID + "/serviceAccounts/" + email
if _, err := iamClient.Projects.ServiceAccounts.Get(desired).Do(); err != nil {
    return fmt.Errorf("pre-flight: cannot read service account %s: %w", email, err)
}

Type guard

func isNotFound(err error) bool {
    var ge *googleapi.Error
    return errors.As(err, &ge) && ge.Code == 404
}

Try / catch

sa, err := cloud.IAM().ServiceAccounts().Get(ctx, fqn)
if err != nil {
    if gce.IsNotFound(err) {
        return nil, nil // treat as absent
    }
    var ge *googleapi.Error
    if errors.As(err, &ge) && ge.Code == 403 {
        return nil, fmt.Errorf("need roles/iam.serviceAccountViewer to read %s: %w", fqn, err)
    }
    return nil, fmt.Errorf("error listing ServiceAccount %q: %w", fqn, err)
}

Prevention

When it happens

Trigger: ServiceAccounts().Get(ctx, fqn) returns permissionDenied, the IAM API is disabled, the email/fqn is malformed (fqn is built as projects/<project>/serviceAccounts/<email>), or a transient Google API error occurs during `kops update cluster --refresh` or apply.

Common situations: Service account was deleted from GCP but still referenced in the cluster spec combined with an API error path (though pure deletion returns NotFound and nil); missing iam.serviceAccounts.get on the credentials kOps uses; IAM API not enabled in a fresh project.

Related errors


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