{"record":{"id":"457665f6b04708a2","repo":"Tencent/WeKnora","slug":"reload-mcp-oauth-token-before-refresh-w","errorCode":null,"errorMessage":"reload MCP OAuth token before refresh: %w","messagePattern":"reload MCP OAuth token before refresh: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_lifecycle.go","lineNumber":198,"sourceCode":"\t}\n}\n\nfunc (r *oauthRuntime) refreshAsLeaseOwner(\n\tctx context.Context, observed *types.MCPOAuthToken, leaseID string, override *transport.OAuthHandler,\n) error {\n\tdefer func() {\n\t\treleaseCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)\n\t\tdefer cancel()\n\t\tif err := r.repo.ReleaseTokenRefreshLease(\n\t\t\treleaseCtx, r.tenantID, r.principal, r.serviceID, leaseID,\n\t\t); err != nil {\n\t\t\tlogger.GetLogger(releaseCtx).Warnf(\"failed to release MCP OAuth refresh lease: %v\", err)\n\t\t}\n\t}()\n\n\tcurrent, err := r.repo.GetTokenForPrincipal(ctx, r.tenantID, r.principal, r.serviceID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reload MCP OAuth token before refresh: %w\", err)\n\t}\n\tif current == nil || current.AccessToken == \"\" {\n\t\treturn &OAuthReauthorizationRequiredError{Reason: \"no token is stored\"}\n\t}\n\t// Another owner may have completed a refresh immediately before this lease\n\t// was acquired. Never consume its newly rotated refresh token unnecessarily.\n\tif oauthTokenMaterialChanged(current, observed) &&\n\t\t(current.ExpiresAt.IsZero() || current.ExpiresAt.After(time.Now().Add(oauthRefreshSkew))) {\n\t\treturn nil\n\t}\n\tif current.RefreshToken == \"\" {\n\t\treturn r.invalidateToken(ctx, false, \"no refresh token is available\")\n\t}\n\n\thandler := override\n\tif handler == nil {\n\t\thandler = r.handler\n\t}","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_lifecycle.go#L180-L216","documentation":"Wraps a repository error that occurred while reloading the stored OAuth token immediately after acquiring the refresh lease, before performing the refresh. refreshAsLeaseOwner must read current token state to decide whether another owner already rotated it; a storage failure here aborts the refresh with this wrapped error.","triggerScenarios":"refreshAsLeaseOwner acquires the refresh lease, calls repo.GetTokenForPrincipal, and the repo returns an error (DB unavailable, context cancelled, query failure).","commonSituations":"Database failover during a refresh; connection pool exhaustion under concurrent refreshes; context deadline exceeded while waiting for the lease then reading; misconfigured DB credentials after rotation.","solutions":["Check the wrapped cause for DB connectivity/auth errors and fix the database connection","Re-run the operation; the lease is released via defer and can be safely re-acquired","Ensure the DB user/credentials used by the repo are valid and not expired","Increase context timeout so lease wait + reload fits within the deadline"],"exampleFix":"// before\ntok, err := rt.EnsureFresh(ctx, tenantID, principal, serviceID)\nif err != nil { return err }\n// after: distinguish transient storage errors and retry\nif err != nil {\n    if isTransientDBError(err) {\n        return retryWithBackoff(ctx, func() error {\n            tok, err = rt.EnsureFresh(ctx, tenantID, principal, serviceID); return err\n        })\n    }\n    return err\n}","handlingStrategy":"retry","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"token store unavailable before refresh: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := rt.Refresh(ctx, tenantID, principal, serviceID)\nif err != nil && strings.Contains(err.Error(), \"reload MCP OAuth token before refresh\") && isTransient(err) {\n    time.Sleep(backoff)\n    err = rt.Refresh(ctx, tenantID, principal, serviceID)\n}\nif err != nil {\n    var reauth *mcp.OAuthReauthorizationRequiredError\n    if errors.As(err, &reauth) { return startReauth(ctx, reauth) }\n    return err\n}","preventionTips":["Ensure the request context outlives the lease wait plus reload","Validate DB credentials after any secret rotation","Set connection pool limits appropriate to concurrent refresh load","Add retry-once logic for transient DB errors"],"tags":["oauth","database","persistence","concurrency"],"backgroundTag":"oauth-token-refresh-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}