different-ai/openwork · error · DenApiError

invalid_mcp_connection_payload

invalid_mcp_connection_payload

Error message

MCP connection connect response was invalid.

What it means

DenApiError thrown by startMcpConnectionConnect in apps/app/src/app/lib/den.ts when the Den API returned a 2xx for GET /v1/mcp-connections/{connectionId}/connect/start, but the response body failed the getDenMcpConnectionConnectStart shape check (missing or malformed connect-start data such as an OAuth authorize URL / session info). The client refuses to return unvalidated data rather than passing a partially-shaped object downstream.

Source

Thrown at apps/app/src/app/lib/den.ts:3394

    async listMcpConnectionPresets(orgId: string): Promise<DenExternalMcpPreset[]> {
      const payload = await requestJson<unknown>(
        baseUrls,
        "/v1/mcp-connections/presets",
        { method: "GET", token, organizationId: orgId },
      );
      return getDenExternalMcpPresets(payload);
    },

    async startMcpConnectionConnect(orgId: string, connectionId: string): Promise<DenMcpConnectionConnectStart> {
      const payload = await requestJson<unknown>(
        baseUrls,
        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/connect/start`,
        { method: "GET", token, organizationId: orgId },
      );
      const result = getDenMcpConnectionConnectStart(payload);
      if (!result) {
        throw new DenApiError(500, "invalid_mcp_connection_payload", "MCP connection connect response was invalid.");
      }
      return result;
    },

    async disconnectOauthProviderAccount(orgId: string, providerId: string): Promise<void> {
      await requestJson<unknown>(
        baseUrls,
        `/v1/oauth-providers/${encodeURIComponent(providerId)}/disconnect`,
        { method: "POST", token, organizationId: orgId },
      );
    },

    async disconnectMyMcpConnectionAccount(orgId: string, connectionId: string): Promise<void> {
      await requestJson<unknown>(
        baseUrls,
        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/disconnect-my-account`,
        { method: "POST", token, organizationId: orgId },
      );

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Log the raw response body from /v1/mcp-connections/:id/connect/start and compare it against the fields getDenMcpConnectionConnectStart expects
  2. Verify the Den server version matches the client: a schema mismatch means upgrade the server or align the client
  3. Confirm the connectionId is valid, exists in the org, and is in a connectable state (list via /v1/mcp-connections first)
  4. Check no proxy/gateway/CDN is rewriting the JSON response into HTML or a login page
  5. Retry after re-authenticating if the token silently fell back to an anonymous/limited session

Example fix

// before
const result = getDenMcpConnectionConnectStart(payload);
if (!result) {
  throw new DenApiError(500, "invalid_mcp_connection_payload", "MCP connection connect response was invalid.");
}
// after
defensive on caller side:
try {
  const start = await client.startMcpConnectionConnect(orgId, connectionId);
} catch (err) {
  if (err instanceof DenApiError && err.code === "invalid_mcp_connection_payload") {
    // inspect raw payload / refresh connection list before retrying
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side pre-check before starting connect
const conns = await client.listMcpConnections(orgId);
const conn = conns.find((c) => c.id === connectionId);
if (!conn) throw new Error(`Unknown MCP connection: ${connectionId}`);

Type guard

function isConnectStart(v: unknown): v is DenMcpConnectionConnectStart {
  return (
    typeof v === "object" && v !== null &&
    "authorizeUrl" in v && typeof (v as { authorizeUrl?: unknown }).authorizeUrl === "string"
  );
}

Try / catch

try {
  const start = await client.startMcpConnectionConnect(orgId, connectionId);
} catch (err) {
  if (err instanceof DenApiError && err.code === "invalid_mcp_connection_payload") {
    // surface 'connect flow unavailable' and let the user retry after refreshing connections
  } else { throw err; }
}

Prevention

When it happens

Trigger: GET /v1/mcp-connections/:id/connect/start returned 200 but the body was an empty object, an error envelope, HTML from a proxy, or lacked the fields getDenMcpConnectionConnectStart requires (e.g. no authorizeUrl/session data); typically when the connectionId exists but the connection is not in a connectable state or the server version's payload schema differs.

Common situations: Pointing the app at a self-hosted or older Den server whose /connect/start endpoint predates the current response schema; a reverse proxy or gateway intercepting the request and returning a 200 page; passing a deleted or wrong-organization connectionId; middleware (mock server, service worker) returning a stubbed body.

Related errors


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