kubernetes/kops · error

error listing Routes: %w

Error message

error listing Routes: %w

What it means

Wraps a failure from Compute Routes().List in listRoutes, which enumerates all routes in the project and filters by cluster-name-with-UUID to find routes owned by the cluster. Any List API failure (this is a full-project listing, so it needs broad compute.routes.list permission) aborts discovery with this wrapped error.

Source

Thrown at pkg/resources/gce/gce.go:748

	c := d.gceCloud

	var resourceTrackers []*resources.Resource

	instancesToDelete := make(map[string]*resources.Resource)
	migsToDelete := make(map[string]*resources.Resource)
	for _, resource := range resourceMap {
		switch resource.Type {
		case typeInstance:
			instancesToDelete[resource.ID] = resource
		case typeInstanceGroupManager:
			migsToDelete[resource.ID] = resource
		}
	}

	// TODO: Push-down prefix?
	routes, err := c.Compute().Routes().List(ctx, c.Project())
	if err != nil {
		return nil, fmt.Errorf("error listing Routes: %w", err)
	}
	for _, r := range routes {
		if !d.matchesClusterNameWithUUID(r.Name, maxGCERouteNameLength) {
			continue
		}
		remove := false
		for _, w := range r.Warnings {
			switch w.Code {
			case "NEXT_HOP_INSTANCE_NOT_FOUND":
				remove = true
			case "NEXT_HOP_NOT_RUNNING":
				// It might not be running, but it probably exists.
				remove = false
			default:
				klog.Infof("Unknown warning on route %q: %q", r.Name, w.Code)
			}
		}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Grant compute.routes.list (roles/compute.networkViewer or compute.networkAdmin) to the credentials, including on shared VPC host projects.
  2. Retry with backoff if the wrapped error is 429/5xx.
  3. Reduce route-table pressure: clean up stale routes in the project if listing times out.
  4. Verify the correct project is configured (cluster in a service project but routes in the host project).
  5. Inspect the wrapped error with errors.As for the precise Google API status.
Defensive patterns

Strategy: retry

Validate before calling

// pre-check list permission cheaply
_, err := computeService.Routes.List(project).PageSize(1).Do()
if err != nil {
    if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 403 {
        return fmt.Errorf("service account lacks compute.routes.list on %s", project)
    }
}

Type guard

func isGCEAPIError(err error) (*googleapi.Error, bool) {
    var gerr *googleapi.Error
    return gerr, errors.As(err, &gerr)
}

Try / catch

routes, err := listRoutes(ctx, c)
if err != nil {
    var gerr *googleapi.Error
    if errors.As(err, &gerr) && (gerr.Code == 429 || gerr.Code >= 500) {
        time.Sleep(backoff); routes, err = listRoutes(ctx, c) // retry once
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: c.Compute().Routes().List(ctx, project) fails with 403 permission denied (routes.list not granted), 429 rate limit on list calls, 5xx, or network/timeout failure for large route tables; also service-account impersonation lacking the right scopes.

Common situations: Shared VPC host project where kops credentials have no routes.list on that project; projects with thousands of routes hitting timeouts/quota; credential rotation removing compute.networkViewer; GCP API outage during kops delete cluster.

Related errors


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