{"record":{"id":"de8e569643784976","repo":"AlexxIT/go2rtc","slug":"request-failed-with-status-d-s","errorCode":null,"errorMessage":"request failed with status %d: %s","messagePattern":"request failed with status (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/ring/api.go","lineNumber":503,"sourceCode":"\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}\n\n\treturn responseBody, nil\n}\n\nfunc (c *RingApi) ensureSession() error {\n\tc.sessionMutex.Lock()\n\tdefer c.sessionMutex.Unlock()\n\n\t// If session is still valid, use it\n\tif c.session != nil && time.Now().Before(c.sessionExpiry) {\n\t\treturn nil\n\t}\n\n\t// Make sure we have a valid auth token","sourceCodeStart":485,"sourceCodeEnd":521,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/ring/api.go#L485-L521","documentation":"The Ring API returned an HTTP status >= 400 that is not 401 (and not a session-related 404), so the client treats it as a terminal failure. The error message embeds the numeric status and the full response body, which contains Ring's own error explanation. This is a pass-through of a server-side rejection of your request.","triggerScenarios":"Any RingApi.Request() call where Ring replies 400 (bad request payload), 403 (forbidden), 404 (real resource missing), 429 (rate limited), or 5xx — outside the 401/session-refresh retry paths.","commonSituations":"Malformed request body for a Ring endpoint, calling a deprecated/renamed Ring endpoint, exceeding Ring's rate limits with rapid polling, requesting devices the account no longer owns, or Ring server errors during outages.","solutions":["Read the body text in the error — it names the exact server-side problem","If status is 429, add backoff/rate-limiting to your polling loop","If 400/404, verify the URL, request body shape, and that the target device/endpoint still exists","If 403, check account permissions/subscription (e.g. Ring Protect) for the requested resource","If 5xx, retry later — it is a Ring-side outage"],"exampleFix":"// before\n_, err := client.Request(\"POST\", url, map[string]interface{}{\"bad\": 1})\n// after\npayload := map[string]interface{}{\"device_id\": id, \"command\": cmd} // match Ring's schema\n_, err := client.Request(\"POST\", url, payload)\nif err != nil {\n    var apiErr *ring.StatusError\n    if errors.As(err, &apiErr) && apiErr.StatusCode == 429 {\n        time.Sleep(30 * time.Second)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// validate inputs the Ring API is strict about before calling\nif deviceID == \"\" || strings.Contains(url, \" \") {\n    return errors.New(\"invalid device id or URL for ring request\")\n}","typeGuard":"type StatusError struct { StatusCode int; Body string }\nfunc asStatusError(err error) (*StatusError, bool) {\n    var se *StatusError\n    if errors.As(err, &se) && se.StatusCode >= 400 { return se, true }\n    return nil, false\n}","tryCatchPattern":"data, err := client.Request(\"GET\", url, nil)\nif se, ok := asStatusError(err); ok {\n    switch se.StatusCode {\n    case 429: rateLimitedBackoff()\n    case 403: return fmt.Errorf(\"permission/subscription issue: %s\", se.Body)\n    default:  return fmt.Errorf(\"ring api error: %s\", se.Body)\n    }\n}","preventionTips":["Parse the response body in the error before retrying blindly","Throttle polling to avoid Ring 429 rate limits","Match request bodies exactly to Ring's current API schema","Handle 5xx with delayed retries as Ring-side outages","Check account subscription/permissions for protected endpoints"],"tags":["http","api-error","ring","status-code"],"backgroundTag":"http-error-response","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"}