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
- Log/capture the failing URL from the error message and inspect it
- Verify you are on the real DigitalOcean API (custom server may emit bad links)
- Check for intermediaries (caching/compressing proxies) altering the JSON body
- 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
- 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
- Avoid caching/compression proxies that alter JSON bodies on the API path
- Use the genuine api.digitalocean.com endpoint for large droplet sets
- Keep per-page sizes default so pagination links are generated normally
- Retry on transient failures — truncated responses cause bad links
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
- unexpected nextLink host %q, expecting %q
- cannot fetch data from digitalocean list api: %w
- failed parse digitalocean api response: %q, err: %w
- cannot create request to %q: %w
- invalid target url=%q for job=%q: %w
AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03).
Data as JSON: /api/errors/d7c4599ba92967c9.
Report an issue: GitHub.