{"record":{"id":"f38019cbbb8a57e4","repo":"Tencent/WeKnora","slug":"reload-mcp-oauth-token-after-concurrent-refresh","errorCode":null,"errorMessage":"reload MCP OAuth token after concurrent refresh: %w","messagePattern":"reload MCP OAuth token after concurrent refresh: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_lifecycle.go","lineNumber":169,"sourceCode":"\t\tleaseUntil := time.Now().Add(leaseDuration)\n\t\tacquired, err := r.repo.TryAcquireTokenRefreshLease(\n\t\t\tctx, r.tenantID, r.principal, r.serviceID, leaseID, leaseUntil,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"claim MCP OAuth token refresh: %w\", err)\n\t\t}\n\t\tif acquired {\n\t\t\treturn r.refreshAsLeaseOwner(ctx, observed, leaseID, override)\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(oauthRefreshPoll):\n\t\t}\n\t\tcurrent, err := r.repo.GetTokenForPrincipal(ctx, r.tenantID, r.principal, r.serviceID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reload MCP OAuth token after concurrent refresh: %w\", err)\n\t\t}\n\t\tif current == nil || current.AccessToken == \"\" {\n\t\t\treturn &OAuthReauthorizationRequiredError{Reason: \"the refresh token is no longer valid\"}\n\t\t}\n\t\tif oauthTokenMaterialChanged(current, observed) {\n\t\t\tif current.ExpiresAt.IsZero() || current.ExpiresAt.After(time.Now().Add(oauthRefreshSkew)) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tobserved = current\n\t\t}\n\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)","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_lifecycle.go#L151-L187","documentation":"Wraps a repository error that occurred while re-reading the stored OAuth token after waiting on the refresh lease poll. After another principal's concurrent refresh completes, the runtime reloads the token to pick up the newly rotated credentials; if that reload fails, the underlying storage error is wrapped and returned to ensureFresh. It signals a persistence-layer problem during the post-refresh reconciliation, not an OAuth protocol failure.","triggerScenarios":"refreshWithLease loses (or waits out) the lease race, then calls repo.GetTokenForPrincipal and the repo returns an error (DB down, connection pool exhausted, context deadline, table missing).","commonSituations":"Database outage or transient network blip mid-refresh; Postgres/MySQL connection limit reached under load; the request context is cancelled while polling oauthRefreshPoll; schema migration left the token table unavailable.","solutions":["Inspect the wrapped cause (%w) for a DB connectivity error and restore the database connection/pool","Retry the token refresh operation once connectivity is restored; the lease mechanism is safe to re-enter","Increase request/context timeouts if cancellation during oauthRefreshPoll is the cause","Verify the token repository table/schema exists for this tenant and service"],"exampleFix":"// before\nlexer := oauth.NewLifecycle(repo)\ntok, err := lexer.EnsureFresh(ctx, svc, principal)\n// after: retry with backoff on transient repo failures\nvar tok *types.Token\nerr := retry.Do(func() error {\n    var e error\n    tok, e = lexer.EnsureFresh(ctx, svc, principal)\n    return e\n}, retry.OnRetry(func(n uint, err error) {\n    log.Warnf(\"retrying oauth refresh after transient error: %v\", 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":"tok, err := rt.EnsureFresh(ctx, tenantID, principal, serviceID)\nif err != nil && strings.Contains(err.Error(), \"reload MCP OAuth token after concurrent refresh\") {\n    // transient repo failure: retry with backoff\n    return backoff.Retry(func() error { _, err = rt.EnsureFresh(ctx, tenantID, principal, serviceID); return err })\n}\nif err != nil {\n    var reauth *mcp.OAuthReauthorizationRequiredError\n    if errors.As(err, &reauth) { return startReauth(ctx, reauth) }\n    return err\n}","preventionTips":["Monitor DB health and pool saturation; alert before exhaustion","Use generous-but-bounded context timeouts around refresh calls","Keep the token table schema migrated and indexed","Wrap repo calls with idempotent retry middleware"],"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"}