AlexxIT/go2rtc · error
failed to refresh session
Error message
failed to refresh session: %w
What it means
After an HTTP 401 the client discards its session and calls ensureSession() to build a new one, but that call returned an error. The library wraps the underlying cause (usually an auth-token or session-creation failure) with this message, so the real reason is in the wrapped %w error.
Solutions
- Inspect the wrapped cause (errors.Unwrap / %v of the error) — fix the underlying auth failure first
- Force a full re-authentication: clear cached auth token and session, then re-run with fresh credentials
- Test the session endpoint manually with your hardware_id to see the raw server response
- Check network connectivity/DNS if the refresh call itself fails at transport level
Example fix
// before
resp, err := client.GetActiveDings() // opaque 'failed to refresh session'
// after
if _, err := client.GetActiveDings(); err != nil {
log.Printf("refresh failed: %+v", err) // reveal wrapped cause
client.ResetAuth() // force clean re-login
} Defensive patterns
Strategy: try-catch
Validate before calling
// check auth health before making API calls
if err := client.EnsureAuth(); err != nil {
return fmt.Errorf("ring auth unhealthy: %w", err)
} Type guard
func isSessionRefreshFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to refresh session")
} Try / catch
data, err := client.GetActiveDings()
if isSessionRefreshFailure(err) {
client.ResetAuth() // clear token+session, re-login
data, err = client.GetActiveDings()
} else if err != nil {
log.Printf("unexpected: %v", err)
} Prevention
- Refresh the session periodically rather than only on 401
- Log errors with %+v to see the wrapped cause
- Keep system clock synced — expired-token logic depends on it
- Cache refresh tokens durably so they stay valid
When it happens
Trigger: Any RingApi.Request() call that receives 401 Unauthorized and whose subsequent ensureSession() fails — e.g. ensureAuth fails to exchange the refresh token, or Ring's session endpoint rejects the new session request.
Common situations: Expired refresh token, Ring session endpoint (oauth/session API) returning 4xx due to changed API contract, network outage between the 401 and the refresh call, or invalid hardware_id sent in the session payload.
Related errors
- authentication failed after
- authentication failed while creating session
- session validation failed
- session refresh failed after
- session request failed with status
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/fcb7dcec9c7d60cc.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/ring/api.go:470
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()
if attempt == maxRetries {
return nil, fmt.Errorf("authentication failed after %d retries", maxRetries)
}
// By 401 with Auth AND Session start over
c.sessionMutex.Lock()
c.session = nil
c.sessionExpiry = time.Time{} // Reset session expiry
c.sessionMutex.Unlock()
if err := c.ensureSession(); err != nil {
return nil, fmt.Errorf("failed to refresh session: %w", err)
}
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 {View on GitHub (pinned to c245815e75)