AlexxIT/go2rtc · error

request failed after

Error message

request failed after %d retries: %w

What it means

RingApi.Request retries httpClient.Do up to maxRetries times, sleeping 5 seconds between attempts. If every attempt fails with a transport-level error (connection refused, DNS failure, TLS error, timeout), it gives up and returns 'request failed after N retries' wrapping the last error. The request reached neither a successful nor an HTTP-level response.

Solutions

  1. Check basic network connectivity and DNS resolution for the Ring API host (curl/ping the endpoint)
  2. Inspect the wrapped error (errors.Unwrap) to identify the root cause: connection refused vs timeout vs TLS
  3. Increase maxRetries or backoff in the client config if the endpoint is intermittently reachable
  4. Configure a proxy (HTTP_PROXY/HTTPS_PROXY) if required by your network
  5. Retry later if it's a Ring-side outage; check Ring status/community forums

Example fix

// before
resp, err := c.httpClient.Do(req) // no timeout, hangs then fails all retries
// after
c.httpClient.Timeout = 30 * time.Second
resp, err := c.httpClient.Do(req)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        return nil, fmt.Errorf("ring api timed out after %d retries: %w", maxRetries, err)
    }
    return nil, fmt.Errorf("request failed after %d retries: %w", maxRetries, err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Go: preflight reachability check before important calls
func reachable(host string) error {
    conn, err := net.DialTimeout("tcp", host+":443", 5*time.Second)
    if err != nil {
        return err
    }
    return conn.Close()
}

Try / catch

// Go: exponential backoff around the library call
var resp []byte
err := retry.Do(func() error {
    var e error
    resp, e = api.Request("GET", url, nil)
    if e != nil && strings.Contains(e.Error(), "request failed after") {
        return retry.Transient(e)
    }
    return retry.Permanent(e)
}, retry.Attempts(3), retry.DelayType(retry.BackOffDelay))

Prevention

When it happens

Trigger: Calling any RingApi.Request when the Ring API endpoint is unreachable for all attempts: network outage, DNS failure, server down, TLS handshake failure, or persistent timeouts.

Common situations: Ring service outage or maintenance; corporate proxy/firewall blocking api.ring.com; local network drop (Wi-Fi down); DNS misconfiguration; timeouts because the client has no deadline configured and the route is saturated.

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 AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/3a0945143ba9d8ef. Report an issue: GitHub.

Appendix: source

Thrown at pkg/ring/api.go:439

		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	// Set headers
	req.Header.Set("Authorization", "Bearer "+c.authToken.AccessToken)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("hardware_id", c.hardwareID)
	req.Header.Set("User-Agent", "android:com.ringapp")

	// Make request with retries
	var resp *http.Response
	var responseBody []byte

	for attempt := 0; attempt <= maxRetries; attempt++ {
		resp, err = c.httpClient.Do(req)
		if err != nil {
			if attempt == maxRetries {
				return nil, fmt.Errorf("request failed after %d retries: %w", maxRetries, err)
			}
			time.Sleep(5 * time.Second)
			continue
		}
		defer resp.Body.Close()

		responseBody, err = io.ReadAll(resp.Body)
		if err != nil {
			return nil, fmt.Errorf("failed to read response body: %w", err)
		}

		// Handle 401 by refreshing auth and retrying
		if resp.StatusCode == http.StatusUnauthorized {
			// Reset token to force refresh
			c.authMutex.Lock()
			c.authToken = nil
			c.tokenExpiry = time.Time{} // Reset token expiry
			c.authMutex.Unlock()

View on GitHub (pinned to c245815e75)