AlexxIT/go2rtc · error

session refresh failed after

Error message

session refresh failed after %d retries

What it means

The client received a 404 on a client-api URL whose error body references the configured hardware_id — meaning Ring no longer recognizes the session registered for this hardware ID. After clearing the session and retrying maxRetries times, every retry still got a session-related 404, so the client gives up. This indicates the hardware_id is not accepted by Ring's client API at all.

Solutions

  1. Generate a fresh random hardware_id in valid format and reinitialize the client
  2. Verify the hardware_id matches what your session creation actually registered
  3. Log in once with an official device to re-register, then reuse that hardware_id
  4. Check that clientAPIBaseURL is current — Ring sometimes changes API hosts

Example fix

// before
c := ring.NewClient(ring.WithHardwareID("")) // empty/invalid ID -> 404 loop
// after
hwID := strings.ToUpper(uuid.NewString())
c := ring.NewClient(ring.WithHardwareID(hwID))
Defensive patterns

Strategy: validation

Validate before calling

hwID := client.HardwareID()
if hwID == "" || len(hwID) < 16 {
    return errors.New("hardware_id missing or malformed; regenerate before calling ring API")
}

Type guard

func isSessionNotFound(err error) bool {
    return err != nil && strings.Contains(err.Error(), "session refresh failed after")
}

Try / catch

devices, err := client.GetDevices()
if isSessionNotFound(err) {
    client.RegenerateHardwareID()
    if err := client.EnsureSession(); err != nil {
        return fmt.Errorf("hard failure, need full re-login: %w", err)
    }
    devices, err = client.GetDevices()
}

Prevention

When it happens

Trigger: Calling any Request() against clientAPIBaseURL endpoints (e.g. ring-doorbell APIs) where every response is 404 with an error string containing your hardware_id, even after session refresh retries are exhausted.

Common situations: Hardware ID generated in a wrong format or duplicated across clients, Ring server-side purged the session, using an old hardware_id that was deregistered, or regional Ring API rejecting unknown device IDs.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/1093e1b6c1669f79. Report an issue: GitHub.

Appendix: source

Thrown at pkg/ring/api.go:489

			}

			req.Header.Set("Authorization", "Bearer "+c.authToken.AccessToken)
			continue
		}

		// Handle 404 error with hardware_id reference - session issue
		if resp.StatusCode == 404 && strings.Contains(url, clientAPIBaseURL) {
			var errorBody map[string]interface{}
			if err := json.Unmarshal(responseBody, &errorBody); err == nil {
				if errorStr, ok := errorBody["error"].(string); ok && strings.Contains(errorStr, c.hardwareID) {
					// Session with hardware_id not found, refresh session
					c.sessionMutex.Lock()
					c.session = nil
					c.sessionExpiry = time.Time{} // Reset session expiry
					c.sessionMutex.Unlock()

					if attempt == maxRetries {
						return nil, fmt.Errorf("session refresh failed after %d retries", maxRetries)
					}

					if err := c.ensureSession(); err != nil {
						return nil, fmt.Errorf("failed to refresh session: %w", err)
					}

					continue
				}
			}
		}

		// Handle other error status codes
		if resp.StatusCode >= 400 {
			return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(responseBody))
		}

		break
	}

View on GitHub (pinned to c245815e75)