kubernetes/kops · error

failed to list vpcs: %v

Error message

failed to list vpcs: %v

What it means

listVPCs wraps any failure from the DigitalOcean API client's GetAllVPCs() call. The library throws it when the underlying godo VPC list request fails (auth, network, API error), aborting discovery of the cluster's 'vpc-<clustername>' VPC resource. The original API error is embedded via %v.

Source

Thrown at pkg/resources/digitalocean/resources.go:462

		if response != nil && response.StatusCode == http.StatusNotFound {
			return nil
		}
		return fmt.Errorf("failed to delete ssh key %s (ID %s): %s", t.Name, t.ID, err)
	}

	return nil
}

func listVPCs(cloud fi.Cloud, clusterName string) ([]*resources.Resource, error) {
	c := cloud.(do.DOCloud)
	var resourceTrackers []*resources.Resource

	clusterName = do.SafeClusterName(clusterName)
	vpcName := "vpc-" + clusterName

	vpcs, err := c.GetAllVPCs()
	if err != nil {
		return nil, fmt.Errorf("failed to list vpcs: %v", err)
	}

	for _, vpc := range vpcs {
		if vpc.Name == vpcName {
			resourceTracker := &resources.Resource{
				Name:    vpc.Name,
				ID:      vpc.ID,
				Type:    resourceTypeVPC,
				Deleter: deleteVPC,
				Obj:     vpc,
			}

			resourceTrackers = append(resourceTrackers, resourceTracker)
		}
	}

	return resourceTrackers, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the DigitalOcean API token is valid and has read scope (doctl auth check or curl -H 'Authorization: Bearer <token>' https://api.digitalocean.com/v2/vpcs).
  2. Inspect the wrapped inner error (%v output) for the real cause: 401 => bad token, 429 => rate limited, 5xx/timeout => DO outage; fix accordingly.
  3. Check network/proxy connectivity from the machine running kops to api.digitalocean.com (DNS, firewall, HTTPS_PROXY settings).
  4. If rate-limited, wait for the rate-limit window to reset and retry; if it's a transient DO incident, retry after api.status.digitalocean.com shows healthy.

Example fix

// before
vpcs, err := c.GetAllVPCs()
if err != nil {
	return nil, fmt.Errorf("failed to list vpcs: %v", err)
}
// after
vpcs, err := c.GetAllVPCs()
if err != nil {
	return nil, fmt.Errorf("failed to list vpcs: %w", err) // preserve chain; callers can errors.Is/As the godo error
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: token must be set and callable
if os.Getenv("DIGITALOCEAN_ACCESS_TOKEN") == "" && doToken == "" {
	return fmt.Errorf("DigitalOcean access token is not configured")
}
// optionally: doctl auth check / GET /v2/vpcs?per_page=1 to confirm API reachability

Type guard

func isDOAPIError(err error) (code int, ok bool) {
	var goe *godo.ErrorResponse
	if errors.As(err, &goe) {
		return goe.Response.StatusCode, true
	}
	return 0, false
}

Try / catch

_, err := c.GetAllVPCs()
if err != nil {
	var goe *godo.ErrorResponse
	switch {
	case errors.As(err, &goe) && goe.Response.StatusCode == http.StatusUnauthorized:
		// refresh DO token
	case errors.As(err, &goe) && goe.Response.StatusCode == http.StatusTooManyRequests:
		// back off and retry after rate-limit reset
	default:
		// transient: retry with backoff
	}
	return fmt.Errorf("failed to list vpcs: %w", err)
}

Prevention

When it happens

Trigger: c.GetAllVPCs() returns an error: invalid/expired DigitalOcean API token, network failure or timeout talking to api.digitalocean.com, DO API 5xx outage, or rate limiting (429) during kops cluster listing/deletion.

Common situations: Running 'kops delete cluster' or 'kops get' against a DigitalOcean cluster with a revoked DO_TOKEN, a misconfigured credentials file, corporate proxy blocking the API, or transient DO API incidents.

Related errors


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