{"record":{"id":"d88b204072fb5d43","repo":"AlexxIT/go2rtc","slug":"nest-unable-to-find-cached-credentials","errorCode":null,"errorMessage":"nest: unable to find cached credentials","messagePattern":"nest: unable to find cached credentials","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nest/api.go","lineNumber":243,"sourceCode":"\t}\n\n\treturn \"\", errors.New(\"nest: max retries exceeded\")\n}\n\nfunc (a *API) refreshToken() error {\n\t// Get the cached API with matching token to get credentials\n\tvar refreshKey string\n\tcacheMu.Lock()\n\tfor key, api := range cache {\n\t\tif api.Token == a.Token {\n\t\t\trefreshKey = key\n\t\t\tbreak\n\t\t}\n\t}\n\tcacheMu.Unlock()\n\n\tif refreshKey == \"\" {\n\t\treturn errors.New(\"nest: unable to find cached credentials\")\n\t}\n\n\t// Parse credentials from cache key\n\tparts := strings.Split(refreshKey, \":\")\n\tif len(parts) != 3 {\n\t\treturn errors.New(\"nest: invalid cache key format\")\n\t}\n\tclientID, clientSecret, refreshToken := parts[0], parts[1], parts[2]\n\n\t// Get new API instance which will refresh the token\n\tnewAPI, err := NewAPI(clientID, clientSecret, refreshToken)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Update current API with new token\n\ta.Token = newAPI.Token\n\ta.ExpiresAt = newAPI.ExpiresAt","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/nest/api.go#L225-L261","documentation":"refreshToken locates the cached API credentials (keyed by a 'host:user:pass'-style composite key) whose token needs refreshing. If the cache walk finds no matching entry, refreshKey stays empty and this error is returned. It means the process has never successfully created an API for these credentials, so there is nothing to refresh from.","triggerScenarios":"Calling refreshToken (via ExchangeSDP) when the credentials cache contains no entry matching the API's credentials — e.g. NewAPI was never called successfully in this process, or the cache was cleared.","commonSituations":"Constructing an API manually/by hand instead of via NewAPI so it never registered in the cache; process restart wiping the in-memory cache; credentials changed so the cache key no longer matches.","solutions":["Create the API through NewAPI (which populates the credentials cache) before operations that may trigger refreshToken.","Re-run the initial authentication flow after a process restart so the cache is repopulated.","Ensure the username/password used matches the one the API was originally created with, so the cache key matches.","If credentials must outlive the process, persist them externally and re-register via NewAPI at startup."],"exampleFix":"// before\napi := &nest.API{...} // built manually; not in cache\nanswer, err := api.ExchangeSDP(ctx, offer)\n\n// after\napi, err := nest.NewAPI(ctx, refreshToken) // registers cache entry\nanswer, err := api.ExchangeSDP(ctx, offer)","handlingStrategy":"validation","validationCode":"// ensure the API was created via NewAPI so credentials are cached\nif !apiWasCreatedViaNewAPI {\n    api, err = nest.NewAPI(ctx, refreshToken)\n    if err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":"answer, err := api.ExchangeSDP(ctx, offer)\nif err != nil && strings.Contains(err.Error(), \"unable to find cached credentials\") {\n    // rebuild the API through NewAPI to repopulate the credential cache\n    api, cerr = nest.NewAPI(ctx, storedRefreshToken)\n    if cerr != nil { return cerr }\n    answer, err = api.ExchangeSDP(ctx, offer)\n}","preventionTips":["Always construct nest APIs via NewAPI; never instantiate the struct directly.","Re-authenticate after process restarts to rebuild the in-memory cache.","Keep credential fields stable so cache keys match across calls.","Persist refresh tokens externally if sessions must survive restarts."],"tags":["nest","cache","credentials","token-refresh"],"backgroundTag":"missing-credentials","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"}