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
- Ensure app.api is an instance of the real Bot Framework ConnectorClient/API client, which has an http transport and a callable constructor.
- Update test doubles to include an http property and construct via the real client class.
- Pin the bot framework SDK version so the client class retains constructor(serviceUrl, http, settings) semantics.
- 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
- Always construct app.api from the SDK's client class, never from plain-object literals.
- In tests, instantiate the real client with fake credentials instead of mocking its shape.
- Pin bot framework SDK versions and re-verify the client's constructor signature on upgrade.
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
- decodeThreadId is unavailable
- openDM is unavailable
- cacheUserContext is unavailable
- getIncomingUser is unavailable
- getUser is unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/91108bce9e45d01d.
Report an issue: GitHub.