tailscale/tailscale · error

fetching %s: %s

Error message

fetching %s: %s

What it means

updateMap received a non-200 HTTP status when fetching the DERP map from d.derpMapURL (for example https://login.tailscale.com/derpmap/default or a self-hosted mirror); res.Status is appended. Note the cached-map fallback in updateMap only applies to transport errors - a non-200 status aborts immediately.

Source

Thrown at prober/derp.go:592

		req, err := http.NewRequestWithContext(ctx, "GET", d.derpMapURL, nil)
		if err != nil {
			return err
		}
		res, err := httpOrFileClient.Do(req)
		if err != nil {
			d.Lock()
			defer d.Unlock()
			if d.lastDERPMap != nil && time.Since(d.lastDERPMapAt) < 10*time.Minute {
				log.Printf("Error while fetching DERP map, using cached one: %s", err)
				// Assume that control is restarting and use
				// the same one for a bit.
				return nil
			}
			return err
		}
		defer res.Body.Close()
		if res.StatusCode != 200 {
			return fmt.Errorf("fetching %s: %s", d.derpMapURL, res.Status)
		}
		dm = new(tailcfg.DERPMap)
		if err := json.NewDecoder(res.Body).Decode(dm); err != nil {
			return fmt.Errorf("decoding %s JSON: %v", d.derpMapURL, err)
		}
	}

	d.Lock()
	defer d.Unlock()
	d.lastDERPMap = dm
	d.lastDERPMapAt = time.Now()
	d.nodes = make(map[string]*tailcfg.DERPNode)
	for _, reg := range d.lastDERPMap.Regions {
		if d.skipRegion(reg) {
			continue
		}

		for _, n := range reg.Nodes {

View on GitHub (pinned to 5201273aec)

Solutions

  1. curl -i the derpMapURL and read the exact status code and body
  2. Fix the -derp-map URL if it is 404/403 (path typo, moved file)
  3. For 429/5xx, retry after the rate limit or incident clears - the prober re-fetches each cycle
  4. Self-host the derpmap JSON at a stable URL if the upstream is flaky

Example fix

// before
prober, _ := NewDerpProber(logf, "https://example.com/derpmap", ..., ...)

// after
prober, _ := NewDerpProber(logf, "https://example.com/derpmap/default.json", ..., ...) // correct path returning 200
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight the map URL before handing it to the prober
resp, err := http.Head(derpMapURL)
if err != nil || resp.StatusCode != 200 {
	return fmt.Errorf("derp map URL unhealthy (%v, status %v); using last known map", err, resp.Status)
}

Try / catch

if err := prober.UpdateMap(ctx); err != nil {
	if strings.Contains(err.Error(), "fetching") {
		// non-200 from control: keep the previous map, retry next cycle
		// (transport errors already fall back to the cache inside updateMap)
	}
}

Prevention

When it happens

Trigger: The map URL returns 403/404/429/5xx: wrong or moved URL, auth-gated mirror, rate limiting, or a control/CDN incident.

Common situations: Typo in the -derp-map flag; corporate proxy intercepting the request; login.tailscale.com outage; a self-hosted derpmap endpoint behind auth or moved paths.

Related errors


AI-assisted analysis of tailscale/tailscale@5201273aec (2026-08-18). Data as JSON: /api/errors/0b6327b037e2b9be. Report an issue: GitHub.