kubernetes/kops · error
error listing ServiceAccounts %w
Error message
error listing ServiceAccounts %w
What it means
Thrown by listServiceAccounts when the IAM ServiceAccounts().List call for projects/<project> fails. kops enumerates project service accounts to find and clean up the cluster-generated control-plane/bastion/node service accounts.
Source
Thrown at pkg/resources/gce/gce.go:1018
op, err := c.Compute().Routers().Delete(u.Project, u.Region, u.Name)
if err != nil {
if gce.IsNotFound(err) {
klog.Infof("Router not found, assuming deleted: %q", o.SelfLink)
return nil
}
return fmt.Errorf("error deleting router %s: %v", o.SelfLink, err)
}
return c.WaitForOp(op)
}
func (d *clusterDiscoveryGCE) listServiceAccounts() ([]*resources.Resource, error) {
c := d.gceCloud
ctx := context.Background()
sas, err := c.IAM().ServiceAccounts().List(ctx, fmt.Sprintf("projects/%s", c.Project()))
if err != nil {
return nil, fmt.Errorf("error listing ServiceAccounts %w", err)
}
var resourceTrackers []*resources.Resource
for _, sa := range sas {
tokens := strings.Split(gce.LastComponent(sa.Name), "@")
if len(tokens) != 2 {
return nil, fmt.Errorf("Invalid service account email '%s'", gce.LastComponent(sa.Name))
}
accountID := tokens[0]
names := []string{gce.ControlPlane, gce.Bastion, gce.Node}
for _, name := range names {
generatedName := gce.ServiceAccountName(name, d.clusterName)
if generatedName == accountID {
resourceTracker := &resources.Resource{
Name: gce.LastComponent(sa.Name),
ID: sa.Name,
Type: typeServiceAccount,
Deleter: deleteServiceAccount,
Obj: sa,View on GitHub (pinned to 4c8573c808)
Solutions
- Enable the IAM API: gcloud services enable iam.googleapis.com.
- Grant roles/iam.serviceAccountViewer (or iam.serviceAccounts.list) to the kops credentials.
- Verify the project in the cluster spec matches the credentials' project (`gcloud config get-value project`).
- Retry on transient errors (429/5xx).
Example fix
// before
return nil, fmt.Errorf("error listing ServiceAccounts %w", err)
// after (distinguish permission errors for a clearer message)
if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 403 {
return nil, fmt.Errorf("error listing ServiceAccounts in project %s (need roles/iam.serviceAccountViewer): %w", c.Project(), err)
}
return nil, fmt.Errorf("error listing ServiceAccounts: %w", err) Defensive patterns
Strategy: validation
Validate before calling
// preflight IAM visibility with gcloud-equivalent check
_, err := iamClient.Projects.ServiceAccounts.List("projects/" + project).Do()
if err != nil {
return fmt.Errorf("cannot list service accounts in %s; grant roles/iam.serviceAccountViewer: %w", project, err)
} Type guard
func isIAMPermissionError(err error) bool {
ge, ok := err.(*googleapi.Error)
return ok && ge.Code == 403
} Try / catch
sas, err := c.IAM().ServiceAccounts().List(ctx, "projects/"+c.Project())
if err != nil {
if isIAMPermissionError(err) {
klog.Warningf("cannot list service accounts (IAM permission); skipping SA cleanup")
return nil, nil
}
return nil, fmt.Errorf("error listing ServiceAccounts: %w", err)
} Prevention
- Enable iam.googleapis.com in the target project.
- Grant roles/iam.serviceAccountViewer to the kops credentials.
- Keep cluster-spec project identical to the credentials' project.
When it happens
Trigger: IAM().ServiceAccounts().List returns an error: 403 (caller lacks iam.serviceAccounts.list, e.g. missing roles/iam.serviceAccountViewer or Service Account Token Creator), invalid project ID in the cluster spec, IAM API disabled, or transient API failure.
Common situations: kops runs with a credentials set that has compute rights but not IAM service-account visibility; project ID mismatch between cluster spec and credentials; iam.googleapis.com disabled in the project.
Related errors
- Invalid service account email '%s'
- error deleting ServiceAccount %s: %v
- error listing ServiceAccount %q: %w
- found ServiceAccount but email did not match expected; got %
- ServiceAccount with email %q not found
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/06671b1b133dd05a.
Report an issue: GitHub.