amir20/dozzle · error

failed to exchange token

Error message

failed to exchange token

What it means

After building the token-exchange request, cloudCallback executes it with the shared cloud HTTP client. Any transport-level failure (DNS, TCP connect, TLS, timeout, context cancellation) results in a 500 with this message. The underlying error is logged with `Failed to exchange token`.

Solutions

  1. Verify the cloud endpoint is reachable from the dozzle host (curl the /api/exchange-token URL).
  2. Check DNS and outbound firewall/proxy settings for the dozzle container.
  3. If using a custom DOLIGENCE_URL, confirm the service is running and the scheme/host are correct.
  4. Retry the cloud connect flow in case of a transient network failure.

Example fix

// before
curl: (6) Could not resolve host: doligence.internal
// after
DOLIGENCE_URL=https://doligence.dozzle.dev  # reachable default endpoint
Defensive patterns

Strategy: retry

Validate before calling

curl -fsS -X POST "${DOLIGENCE_URL:-https://doligence.dozzle.dev}/api/exchange-token?token=test" -o /dev/null && echo reachable

Try / catch

try {
  await connectCloud();
} catch (err) {
  if (isNetworkError(err)) await retryWithBackoff(connectCloud);
  else throw err;
}

Prevention

When it happens

Trigger: The POST to `{cloudURL}/api/exchange-token` fails at transport level: cloud service unreachable, DNS failure, TLS error, network outage, or the request context was cancelled because the user aborted the callback request.

Common situations: DOLIGENCE_URL points at an internal/self-hosted endpoint that is down or unreachable from the dozzle container; firewall blocks egress; DNS misconfiguration; corporate proxy required but not configured.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/11035a5b42a855e5. Report an issue: GitHub.

Appendix: source

Thrown at internal/web/cloud.go:74

	exchangeURL := fmt.Sprintf("%s/api/exchange-token", cloudURL)

	client := cloudHTTPClient
	req, err := http.NewRequestWithContext(r.Context(), http.MethodPost, exchangeURL, nil)
	if err != nil {
		log.Error().Err(err).Msg("Failed to create request")
		http.Error(w, "failed to create request", http.StatusInternalServerError)
		return
	}
	req.Header.Set("User-Agent", dispatcher.UserAgent)
	q := req.URL.Query()
	q.Set("token", token)
	req.URL.RawQuery = q.Encode()

	resp, err := client.Do(req)
	if err != nil {
		log.Error().Err(err).Msg("Failed to exchange token")
		http.Error(w, "failed to exchange token", http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
		log.Error().Int("status", resp.StatusCode).Str("body", string(body)).Msg("Token exchange failed")
		http.Error(w, "token exchange failed", http.StatusInternalServerError)
		return
	}

	var tokenResp exchangeTokenResponse
	if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
		log.Error().Err(err).Msg("Failed to decode token response")
		http.Error(w, "failed to decode token response", http.StatusInternalServerError)
		return
	}

View on GitHub (pinned to d9463cbe21)