cloudflare/cloudflared · error

quick tunnel provisioning failed with status

Error message

quick tunnel provisioning failed with status %d: %s

What it means

RunQuickTunnel provisions a free trycloudflare.com quick tunnel via an HTTP API. When the response status code is outside 2xx and the response body parses as a QuickTunnelResponse containing structured errors, cloudflared surfaces the status code plus the formatted API errors. This is the API's structured error path.

Solutions

  1. Read the formatted API errors in the message and address the specific cause (e.g. wait out a rate limit)
  2. Retry after a short delay — quick-tunnel provisioning is a free shared service and transient 5xx/429s are common
  3. Check the Cloudflare status page for ongoing incidents; use a named tunnel instead if you need guaranteed availability
  4. Verify no corporate proxy/TLS interception is altering the request to the provisioning API
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Get(quickTunnelEndpoint)
if err == nil && resp.StatusCode >= 400 {
    return fmt.Errorf("quick tunnel API unhealthy (status %d); use a named tunnel", resp.StatusCode)
}

Type guard

func is2xx(code int) bool { return code >= 200 && code < 300 }

Try / catch

tunnel, err := RunQuickTunnel(c)
if err != nil {
    log.Error().Err(err).Msg("quick tunnel provisioning failed; retrying with backoff")
    // retry with exponential backoff, or fall back to named tunnel
}

Prevention

When it happens

Trigger: The quick-tunnel provisioning endpoint (api.trycloudflare.com) returns a 4xx/5xx with a JSON body whose `errors` array is non-empty — e.g. rate limiting, service outage, or rejected requests.

Common situations: Running `cloudflared tunnel --url localhost:8080` behind a corporate proxy that intercepts the request; Cloudflare API incidents; too many quick tunnels from one IP hitting rate limits.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/f3857bce2074c5b4. Report an issue: GitHub.

Appendix: source

Thrown at cmd/cloudflared/tunnel/quick_tunnel.go:86

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("User-Agent", buildInfo.UserAgent())

	resp, err := client.Do(req)
	if err != nil {
		return errors.Wrap(err, "failed to request quick Tunnel")
	}
	defer func() { _ = resp.Body.Close() }()

	// This will read the entire response into memory so we can print it in case of error
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return errors.Wrap(err, "failed to read quick-tunnel response")
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		var data QuickTunnelResponse
		if err := json.Unmarshal(respBody, &data); err == nil && len(data.Errors) > 0 {
			return fmt.Errorf("quick tunnel provisioning failed with status %d: %s", resp.StatusCode, formatQuickTunnelErrors(data.Errors))
		}
		return fmt.Errorf("quick tunnel provisioning failed with status %d: %s", resp.StatusCode, string(respBody))
	}

	var data QuickTunnelResponse
	if err := json.Unmarshal(respBody, &data); err != nil {
		respString := string(respBody)
		fields := map[string]interface{}{"status_code": resp.Status}
		sc.log.Err(err).Fields(fields).Msgf("Error unmarshaling QuickTunnel response: %s", respString)
		return errors.Wrap(err, "failed to unmarshal quick Tunnel")
	}

	// TODO(TUN-10791): Add CLI-level coverage that provisioning errors are logged to users.
	if len(data.Errors) > 0 {
		return fmt.Errorf("quick tunnel provisioning failed: %s", formatQuickTunnelErrors(data.Errors))
	}

	if !data.Success {

View on GitHub (pinned to 2253eeeb25)