paperclipai/paperclip · error · TeamsAdapterCompatibilityError

the API client constructor or HTTP transport is unavailable

Error message

the API client constructor or HTTP transport is unavailable

What it means

The wrapper rebuilds a per-conversation API client by invoking defaultApi.constructor as (serviceUrl, http, settings) and reusing defaultApi.http. Before doing so it verifies that the API client has a usable constructor and an 'http' transport property. If either is absent, scoping egress is impossible and the compatibility error is thrown.

Source

Thrown at server/src/services/chat-sdk-runtime.ts:1039

  if (typeof teams.cacheUserContext !== "function") {
    throw new TeamsAdapterCompatibilityError("cacheUserContext is unavailable");
  }
  if (typeof teams.getIncomingUser !== "function") {
    throw new TeamsAdapterCompatibilityError("getIncomingUser is unavailable");
  }
  if (typeof teams.getUser !== "function") {
    throw new TeamsAdapterCompatibilityError("getUser is unavailable");
  }
  for (const methodName of TEAMS_THREAD_SCOPED_METHODS) {
    if (typeof teams[methodName] !== "function") {
      throw new TeamsAdapterCompatibilityError(`${methodName} is unavailable`);
    }
  }
  if (
    typeof teams.app.api.constructor !== "function" ||
    !("http" in teams.app.api)
  ) {
    throw new TeamsAdapterCompatibilityError(
      "the API client constructor or HTTP transport is unavailable",
    );
  }
  const apiDescriptor = Object.getOwnPropertyDescriptor(teams.app, "api");
  if (apiDescriptor && apiDescriptor.configurable === false) {
    throw new TeamsAdapterCompatibilityError(
      "app.api cannot be scoped per asynchronous conversation",
    );
  }
  const trustedConfiguredApiUrl = configuredApiUrl
    ? normalizedTeamsServiceUrl(configuredApiUrl)
    : null;

  // The pinned Teams adapter caches activity/user metadata and may query the
  // members or Graph APIs before Chat dispatches to Paperclip's reach and
  // tenant checks. Keep authenticated but unadmitted events observationally
  // inert. Accepted activities explicitly persist the minimum routing context
  // through paperclipRecordAcceptedActivity below.

View on GitHub (pinned to 01ad858492)

Solutions

  1. Ensure app.api is an instance of the real Bot Framework ConnectorClient/API client, which has an http transport and a callable constructor.
  2. Update test doubles to include an http property and construct via the real client class.
  3. Pin the bot framework SDK version so the client class retains constructor(serviceUrl, http, settings) semantics.
  4. Log typeof api.constructor and 'http' in api at startup to catch shape drift early.

Example fix

// before
app.api = { get: fn } as any; // no http, no constructor
// after
import { ConnectorClient } from 'botframework-connector';
app.api = new ConnectorClient(credentials, { baseUri: serviceUrl }); // real client with http + constructor
Defensive patterns

Strategy: type-guard

Validate before calling

const api = adapter.app?.api;
if (!api || typeof api.constructor !== 'function' || !('http' in api)) {
  throw new Error('app.api must be a real Bot Framework API client with http transport');
}

Type guard

function isScopedApiCandidate(api: unknown): api is { constructor: new (...a: unknown[]) => object; http: unknown } {
  return typeof api === 'object' && api !== null && typeof (api as any).constructor === 'function' && 'http' in (api as any);
}

Try / catch

try {
  scoped = scopeMicrosoftTeamsEgress(adapter);
} catch (err) {
  if (err instanceof TeamsAdapterCompatibilityError && /API client constructor/.test(err.message)) {
    logger.error('app.api is not a real API client instance — replace mocks with ConnectorClient');
  }
  throw err;
}

Prevention

When it happens

Trigger: teams.app.api is not a real Bot Framework API client instance — e.g. it is a plain object mock without an 'http' property, or its constructor is not a function (Object.create(null)-based mock, arrow-function-based factory output).

Common situations: Test doubles that stub app.api with a hand-made object lacking http; a different bot SDK version where the client shape changed; dependency-injected fake API clients in unit tests of the Teams runtime.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/91108bce9e45d01d. Report an issue: GitHub.