Tencent/WeKnora · error

reload MCP OAuth token before refresh: %w

Error message

reload MCP OAuth token before refresh: %w

What it means

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.

Source

Thrown at internal/mcp/oauth_lifecycle.go:198

	}
}

func (r *oauthRuntime) refreshAsLeaseOwner(
	ctx context.Context, observed *types.MCPOAuthToken, leaseID string, override *transport.OAuthHandler,
) error {
	defer func() {
		releaseCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
		defer cancel()
		if err := r.repo.ReleaseTokenRefreshLease(
			releaseCtx, r.tenantID, r.principal, r.serviceID, leaseID,
		); err != nil {
			logger.GetLogger(releaseCtx).Warnf("failed to release MCP OAuth refresh lease: %v", err)
		}
	}()

	current, err := r.repo.GetTokenForPrincipal(ctx, r.tenantID, r.principal, r.serviceID)
	if err != nil {
		return fmt.Errorf("reload MCP OAuth token before refresh: %w", err)
	}
	if current == nil || current.AccessToken == "" {
		return &OAuthReauthorizationRequiredError{Reason: "no token is stored"}
	}
	// Another owner may have completed a refresh immediately before this lease
	// was acquired. Never consume its newly rotated refresh token unnecessarily.
	if oauthTokenMaterialChanged(current, observed) &&
		(current.ExpiresAt.IsZero() || current.ExpiresAt.After(time.Now().Add(oauthRefreshSkew))) {
		return nil
	}
	if current.RefreshToken == "" {
		return r.invalidateToken(ctx, false, "no refresh token is available")
	}

	handler := override
	if handler == nil {
		handler = r.handler
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Check the wrapped cause for DB connectivity/auth errors and fix the database connection
  2. Re-run the operation; the lease is released via defer and can be safely re-acquired
  3. Ensure the DB user/credentials used by the repo are valid and not expired
  4. Increase context timeout so lease wait + reload fits within the deadline

Example fix

// before
tok, err := rt.EnsureFresh(ctx, tenantID, principal, serviceID)
if err != nil { return err }
// after: distinguish transient storage errors and retry
if err != nil {
    if isTransientDBError(err) {
        return retryWithBackoff(ctx, func() error {
            tok, err = rt.EnsureFresh(ctx, tenantID, principal, serviceID); return err
        })
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

if err := db.PingContext(ctx); err != nil {
    return fmt.Errorf("token store unavailable before refresh: %w", err)
}

Try / catch

err := rt.Refresh(ctx, tenantID, principal, serviceID)
if err != nil && strings.Contains(err.Error(), "reload MCP OAuth token before refresh") && isTransient(err) {
    time.Sleep(backoff)
    err = rt.Refresh(ctx, tenantID, principal, serviceID)
}
if err != nil {
    var reauth *mcp.OAuthReauthorizationRequiredError
    if errors.As(err, &reauth) { return startReauth(ctx, reauth) }
    return err
}

Prevention

When it happens

Trigger: refreshAsLeaseOwner acquires the refresh lease, calls repo.GetTokenForPrincipal, and the repo returns an error (DB unavailable, context cancelled, query failure).

Common situations: 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.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/457665f6b04708a2. Report an issue: GitHub.