{"record":{"id":"f2c90e11d7390fdd","repo":"AlexxIT/go2rtc","slug":"refresh-token-is-required","errorCode":null,"errorMessage":"refresh token is required","messagePattern":"refresh token is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/ring/api.go","lineNumber":163,"sourceCode":"\tclientAPIBaseURL   = \"https://api.ring.com/clients_api/\"\n\tdeviceAPIBaseURL   = \"https://api.ring.com/devices/v1/\"\n\tcommandsAPIBaseURL = \"https://api.ring.com/commands/v1/\"\n\tappAPIBaseURL      = \"https://prd-api-us.prd.rings.solutions/api/v1/\"\n\toauthURL           = \"https://oauth.ring.com/oauth/token\"\n\tapiVersion         = 11\n\tdefaultTimeout     = 20 * time.Second\n\tmaxRetries         = 3\n\tsessionValidTime   = 12 * time.Hour\n)\n\nfunc NewRestClient(auth interface{}, onTokenRefresh func(string)) (*RingApi, error) {\n\tvar cacheKey string\n\n\t// Create cache key based on auth data\n\tswitch a := auth.(type) {\n\tcase RefreshTokenAuth:\n\t\tif a.RefreshToken == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"refresh token is required\")\n\t\t}\n\t\tcacheKey = \"refresh:\" + a.RefreshToken\n\tcase EmailAuth:\n\t\tif a.Email == \"\" || a.Password == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"email and password are required\")\n\t\t}\n\t\tcacheKey = \"email:\" + a.Email + \":\" + a.Password\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid auth type\")\n\t}\n\n\tcacheMutex.Lock()\n\tdefer cacheMutex.Unlock()\n\n\tif cachedClient, ok := clientCache[cacheKey]; ok {\n\t\t// Check if token is not nil and not expired\n\t\tif cachedClient.authToken != nil && time.Now().Before(cachedClient.tokenExpiry) {\n\t\t\tcachedClient.onTokenRefresh = onTokenRefresh","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/ring/api.go#L145-L181","documentation":"The Ring client factory requires a non-empty RefreshToken when auth is provided as RefreshTokenAuth. An empty token cannot form a cache key nor authenticate, so the call fails immediately with this error.","triggerScenarios":"Passing ring.RefreshTokenAuth{RefreshToken: \"\"} (zero-value struct) or a variable that was never populated to the Ring client constructor.","commonSituations":"Config file/env var for the refresh token missing or empty; after a refactor the token field was renamed and no longer filled; tokens loaded from secrets manager returned empty string on failure that was ignored.","solutions":["Obtain a valid refresh token (via ring auth flow /, per ring-client-api docs) and pass it in RefreshTokenAuth.","Check the env var/config key holding the token is set and non-empty before constructing the client.","Fail fast at startup: validate the token string before calling the library.","Log the length (never the value) of the token to confirm it is loaded."],"exampleFix":"// before\nclient, _ := ring.NewClient(ring.RefreshTokenAuth{RefreshToken: os.Getenv(\"RING_TOKEN\")})\n// after\nrt := os.Getenv(\"RING_TOKEN\")\nif rt == \"\" {\n    return fmt.Errorf(\"RING_TOKEN must be set\")\n}\nclient, err := ring.NewClient(ring.RefreshTokenAuth{RefreshToken: rt})","handlingStrategy":"validation","validationCode":"if auth.RefreshToken == \"\" { return errors.New(\"ring refresh token must be configured before NewClient\") }","typeGuard":null,"tryCatchPattern":"client, err := ring.NewClient(ring.RefreshTokenAuth{RefreshToken: rt})\nif err != nil {\n    if err.Error() == \"refresh token is required\" {\n        return fmt.Errorf(\"config: RING_REFRESH_TOKEN not set: %w\", err)\n    }\n    return err\n}","preventionTips":["Validate all auth config at process startup, fail fast","Keep tokens in env vars or a secrets manager, never hardcode","Log token presence (length) rather than value when debugging config","Persist refreshed tokens so they are available on restart"],"tags":["go","ring","auth","config"],"backgroundTag":"missing-required-argument","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}