{"record":{"id":"1093e1b6c1669f79","repo":"AlexxIT/go2rtc","slug":"session-refresh-failed-after-d-retries","errorCode":null,"errorMessage":"session refresh failed after %d retries","messagePattern":"session refresh failed after (.+?) retries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/ring/api.go","lineNumber":489,"sourceCode":"\t\t\t}\n\n\t\t\treq.Header.Set(\"Authorization\", \"Bearer \"+c.authToken.AccessToken)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Handle 404 error with hardware_id reference - session issue\n\t\tif resp.StatusCode == 404 && strings.Contains(url, clientAPIBaseURL) {\n\t\t\tvar errorBody map[string]interface{}\n\t\t\tif err := json.Unmarshal(responseBody, &errorBody); err == nil {\n\t\t\t\tif errorStr, ok := errorBody[\"error\"].(string); ok && strings.Contains(errorStr, c.hardwareID) {\n\t\t\t\t\t// Session with hardware_id not found, refresh session\n\t\t\t\t\tc.sessionMutex.Lock()\n\t\t\t\t\tc.session = nil\n\t\t\t\t\tc.sessionExpiry = time.Time{} // Reset session expiry\n\t\t\t\t\tc.sessionMutex.Unlock()\n\n\t\t\t\t\tif attempt == maxRetries {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"session refresh failed after %d retries\", maxRetries)\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := c.ensureSession(); err != nil {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"failed to refresh session: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle other error status codes\n\t\tif resp.StatusCode >= 400 {\n\t\t\treturn nil, fmt.Errorf(\"request failed with status %d: %s\", resp.StatusCode, string(responseBody))\n\t\t}\n\n\t\tbreak\n\t}","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/ring/api.go#L471-L507","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Generate a fresh random hardware_id in valid format and reinitialize the client","Verify the hardware_id matches what your session creation actually registered","Log in once with an official device to re-register, then reuse that hardware_id","Check that clientAPIBaseURL is current — Ring sometimes changes API hosts"],"exampleFix":"// before\nc := ring.NewClient(ring.WithHardwareID(\"\")) // empty/invalid ID -> 404 loop\n// after\nhwID := strings.ToUpper(uuid.NewString())\nc := ring.NewClient(ring.WithHardwareID(hwID))","handlingStrategy":"validation","validationCode":"hwID := client.HardwareID()\nif hwID == \"\" || len(hwID) < 16 {\n    return errors.New(\"hardware_id missing or malformed; regenerate before calling ring API\")\n}","typeGuard":"func isSessionNotFound(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"session refresh failed after\")\n}","tryCatchPattern":"devices, err := client.GetDevices()\nif isSessionNotFound(err) {\n    client.RegenerateHardwareID()\n    if err := client.EnsureSession(); err != nil {\n        return fmt.Errorf(\"hard failure, need full re-login: %w\", err)\n    }\n    devices, err = client.GetDevices()\n}","preventionTips":["Generate hardware_id as a proper random UUID at first run and persist it","Avoid sharing one hardware_id across many clients","Re-register the hardware_id if Ring purges sessions","Pin to a maintained fork/version matching current Ring client-api base URL"],"tags":["session","http-404","hardware-id","ring"],"backgroundTag":"record-not-found","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}