Tencent/WeKnora · error
delete invalid MCP OAuth client registration: %w
Error message
delete invalid MCP OAuth client registration: %w
What it means
Wraps a repository error from DeleteClient when invalidating an OAuth token with resetClient=true. This happens when the client registration itself is considered bad (e.g. permanent registration failures), so both token and dynamic client registration are deleted; the function then returns OAuthReauthorizationRequiredError regardless. A failure here means the stale client registration persists.
Source
Thrown at internal/mcp/oauth_lifecycle.go:247
return &OAuthRefreshTemporaryError{Err: refreshErr}
}
func oauthTokenMaterialChanged(current, observed *types.MCPOAuthToken) bool {
if current == nil || observed == nil {
return current != observed
}
return current.AccessToken != observed.AccessToken ||
current.RefreshToken != observed.RefreshToken ||
!current.ExpiresAt.Equal(observed.ExpiresAt)
}
func (r *oauthRuntime) invalidateToken(ctx context.Context, resetClient bool, reason string) error {
if err := r.repo.DeleteTokenForPrincipal(ctx, r.tenantID, r.principal, r.serviceID); err != nil {
return fmt.Errorf("delete invalid MCP OAuth token: %w", err)
}
if resetClient {
if err := r.repo.DeleteClient(ctx, r.tenantID, r.serviceID); err != nil {
return fmt.Errorf("delete invalid MCP OAuth client registration: %w", err)
}
}
return &OAuthReauthorizationRequiredError{Reason: reason}
}
func permanentRefreshFailure(err error) (permanent bool, resetClient bool) {
var oauthErr transport.OAuthError
if errors.As(err, &oauthErr) {
switch strings.ToLower(oauthErr.ErrorCode) {
case "invalid_grant", "invalid_token", "bad_refresh_token", "expired_token":
return true, false
case "invalid_client", "unauthorized_client":
return true, true
}
}
lower := strings.ToLower(err.Error())
if strings.Contains(lower, "status 400") {
return true, falseView on GitHub (pinned to 988cbb0330)
Solutions
- Grant the repo DB user DELETE privileges on the client registration table
- Verify the client row exists / handle already-deleted as success and retry
- Check DB health (read-only mode, connectivity) indicated by the wrapped cause
- Re-run authorization; dynamic registration will re-register the client if the row is gone
Example fix
// before
if err := m.repo.DeleteClient(ctx, tenantID, serviceID); err != nil {
return err
}
// after: tolerate not-exists, surface real failures
if err := m.repo.DeleteClient(ctx, tenantID, serviceID); err != nil && !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("delete invalid MCP OAuth client registration: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify client table is writable before starting OAuth flows
if err := db.PingContext(ctx); err != nil { return err } Try / catch
err := mgr.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, "")
if err != nil && strings.Contains(err.Error(), "delete invalid MCP OAuth client registration") {
// stale registration persists; fall back to manual cleanup then retry once
_ = repo.DeleteClient(ctx, tenantID, svc.ID)
err = mgr.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, "")
}
if err != nil { return err } Prevention
- Grant DELETE privileges on the oauth client table
- Treat 'row not found' on delete as success to avoid spurious failures
- Keep token+client deletion in a transaction when possible
- Alert on invalidation failures; they block user reauthorization
When it happens
Trigger: invalidateToken(resetClient=true) succeeds deleting the token but repo.DeleteClient fails (DB error, missing privileges, connection loss).
Common situations: DELETE privilege missing on the oauth client table; DB read-only replica; transient network error between the two delete calls; client row already deleted by a concurrent invalidation.
Related errors
- reload MCP OAuth token after concurrent refresh: %w
- reload MCP OAuth token before refresh: %w
- delete invalid MCP OAuth token: %w
- failed to create chunk: %w
- list %s pages: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/5096135dc8466e46.
Report an issue: GitHub.