different-ai/openwork · critical · EnterpriseMcpClientError

MCP_AUTHORIZATION_CALLBACK_FAILED

MCP_AUTHORIZATION_CALLBACK_FAILED

Error message

Enterprise MCP failed during ${phaseLabel[input.operationPhase]}${request}.

What it means

In completeAuthorization(), the authorization code was exchanged (tokens saved) but the subsequent validation (protocol handshake / tools/list) failed, AND the cleanup attempt to invalidate the just-exchanged credentials via credentialPort.invalidate() also failed. The client wraps both failures in an AggregateError inside an EnterpriseMcpClientError with operationPhase "authorization-callback" and code MCP_AUTHORIZATION_CALLBACK_FAILED. This is serious: possibly-orphaned OAuth credentials remain persisted and unvalidated.

Source

Thrown at packages/enterprise-mcp-client/src/enterprise-mcp-client.ts:572

            operationFailed = true
            let credentialCleanupError: unknown = null
            if (exchangedTokens && credentialPort) {
              try {
                const cleanupController = new AbortController()
                await credentialPort.invalidate({
                  context: {
                    connectionId: input.connection.id,
                    commitExpiresAt: clock.now() + closeTimeoutMs,
                    signal: cleanupController.signal,
                  },
                  reason: "post-authorization-validation-failed",
                })
              } catch (cleanupError) {
                credentialCleanupError = cleanupError
              }
            }
            if (credentialCleanupError) {
              throw new EnterpriseMcpClientError({
                operationPhase: "authorization-callback",
                requestPhase: session.observer.lastRequestPhase(),
                cause: new AggregateError(
                  [error, credentialCleanupError],
                  "Post-authorization validation failed and the exchanged credentials could not be invalidated.",
                ),
              })
            }
            throw error
          } finally {
            try {
              await closeWithinDeadline(() => session.client.close(), closeTimeoutMs)
            } catch (error) {
              if (!operationFailed) {
                throw new EnterpriseMcpClientError({
                  operationPhase: "shutdown",
                  requestPhase: session.observer.lastRequestPhase(),
                  cause: error,

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Inspect the AggregateError's two causes: the primary validation failure and the cleanup failure; fix each accordingly.
  2. Manually invalidate the exchanged credentials for this connectionId in your persistence store to avoid orphaned tokens.
  3. Check the persistence adapter's health and its commit deadline handling; increase the lifecycle window if it expired mid-callback.
  4. Retry completeAuthorization after cleanup is possible; the exchange may need to be redone from a fresh authorization code.
Defensive patterns

Strategy: try-catch

Validate before calling

async function assertPersistenceHealthy(credentialsPort) {
  // cheap probe that the credential store accepts writes before exchanging the code
  await credentialsPort.ping?.();
}

Type guard

function isAggregateCleanupError(e: unknown): e is AggregateError {
  return e instanceof AggregateError && e.message.includes("could not be invalidated");
}

Try / catch

try {
  await client.completeAuthorization(input);
} catch (e) {
  if (e.code === "MCP_AUTHORIZATION_CALLBACK_FAILED") {
    const [validationError, cleanupError] = e.cause?.errors ?? [];
    // 1) manually invalidate credentials for connectionId, 2) restart OAuth from a fresh code
  }
  throw e;
}

Prevention

When it happens

Trigger: finishAuth(code) succeeds, then connectWithProtocolNegotiation or listTools throws (e.g. server 401/5xx/network drop), then persistence.credentials.invalidate({ reason: "post-authorization-validation-failed" }) also throws (persistence backend down, commit deadline expired, signal aborted).

Common situations: Persistence adapter (database) outage coinciding with a failing MCP server; lifecycle deadline expiring mid-callback; the OAuth adapter rejecting the invalidation because the transaction already committed or the signal was aborted.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/f2008e1a73c0b01a. Report an issue: GitHub.