VictoriaMetrics/VictoriaMetrics · error

cannot parse digital ocean next url: %s: %w

Error message

cannot parse digital ocean next url: %s: %w

What it means

DigitalOcean paginates droplet lists via links.pages.next URL. nextURLPath parses that URL with url.Parse and converts it to a request path; this error fires when the 'next' URL returned by the API is not parseable, including the offending URL in the message.

Source

Thrown at lib/promscrape/discovery/digitalocean/digitalocean.go:119

	Links    links     `json:"links"`
}

type links struct {
	Pages linksPages `json:"pages"`
}

type linksPages struct {
	Last string `json:"last,omitempty"`
	Next string `json:"next,omitempty"`
}

func (r *listDropletResponse) nextURLPath() (string, error) {
	if r.Links.Pages.Next == "" {
		return "", nil
	}
	u, err := url.Parse(r.Links.Pages.Next)
	if err != nil {
		return "", fmt.Errorf("cannot parse digital ocean next url: %s: %w", r.Links.Pages.Next, err)
	}
	return u.RequestURI(), nil
}

func addDropletLabels(droplets []droplet, defaultPort int) []*promutil.Labels {
	var ms []*promutil.Labels
	for _, droplet := range droplets {
		if len(droplet.Networks.V4) == 0 {
			continue
		}

		privateIPv4 := droplet.getIPByNet("v4", "private")
		publicIPv4 := droplet.getIPByNet("v4", "public")
		publicIPv6 := droplet.getIPByNet("v6", "public")

		addr := discoveryutil.JoinHostPort(publicIPv4, defaultPort)
		m := promutil.NewLabels(16)
		m.Add("__address__", addr)

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Log/capture the failing URL from the error message and inspect it
  2. Verify you are on the real DigitalOcean API (custom server may emit bad links)
  3. Check for intermediaries (caching/compressing proxies) altering the JSON body
  4. Retry the discovery — a transiently truncated response can produce a bad link; if persistent, report to DigitalOcean or pin to a known-good refresh window
  5. As a workaround, reduce per-page droplet count or filter targets so pagination isn't triggered

Example fix

# before (mock server emits bad link)
{"links":{"pages":{"next":"https//api.digitalocean.com/v2/droplets?page=2"}}}

# after
{"links":{"pages":{"next":"https://api.digitalocean.com/v2/droplets?page=2"}}}
Defensive patterns

Strategy: retry

Validate before calling

# Ensure responses come straight from the real API (no rewriting proxies):
curl -fsS -H "Authorization: Bearer $DO_TOKEN" 'https://api.digitalocean.com/v2/droplets?per_page=200&page=2' | jq -r '.links.pages.next // empty'
# If present, it must be an absolute https:// URL

Try / catch

nextURL, err := apiResp.nextURLPath()
if err != nil {
    // log the offending URL embedded in the error, then retry the discovery cycle
    return nil, err
}

Prevention

When it happens

Trigger: DigitalOcean API returns a links.pages.next value that is not a valid absolute URL (malformed, empty scheme with bad characters, relative garbage), typically due to an API behavior change or a proxy rewriting the body.

Common situations: API version drift or a mock/custom 'server' endpoint emitting handcrafted pagination links; HTML-escaped or truncated JSON from a caching proxy; unexpectedly large droplet counts hitting an edge case in the API's link generation.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/d7c4599ba92967c9. Report an issue: GitHub.