paperclipai/paperclip · error · TeamsAdapterCompatibilityError
getUser is unavailable
Error message
getUser is unavailable
What it means
As part of the same compatibility audit, scopeMicrosoftTeamsEgress requires the Teams adapter to expose getUser, because it replaces it with a stub (async () => null) to keep pre-admission Teams events inert. If the method is absent the adapter is considered incompatible and the wrapper throws instead of proceeding with partially-stubbed behavior.
Source
Thrown at server/src/services/chat-sdk-runtime.ts:1028
): Adapter {
const teams = adapter as unknown as TeamsAdapterInternals;
if (!teams.app?.api) {
throw new TeamsAdapterCompatibilityError("app.api is unavailable");
}
if (typeof teams.decodeThreadId !== "function") {
throw new TeamsAdapterCompatibilityError("decodeThreadId is unavailable");
}
if (typeof teams.openDM !== "function") {
throw new TeamsAdapterCompatibilityError("openDM is unavailable");
}
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",View on GitHub (pinned to 01ad858492)
Solutions
- Confirm typeof adapter.getUser === 'function' before calling scopeMicrosoftTeamsEgress.
- Restore or upgrade the official Teams adapter so getUser exists.
- In tests, provide a getUser stub (async () => null is sufficient) on the mock adapter.
- Check that subclassing or proxying the adapter has not shadowed or removed the method.
Example fix
// before
const mock = { app, decodeThreadId, openDM };
scopeMicrosoftTeamsEgress(mock as unknown as Adapter);
// after
const mock = { app, decodeThreadId, openDM, getUser: async () => null, getIncomingUser: async () => null, cacheUserContext: () => {} };
scopeMicrosoftTeamsEgress(mock as unknown as Adapter); Defensive patterns
Strategy: validation
Validate before calling
if (typeof adapter.getUser !== 'function') {
throw new Error('Teams adapter missing getUser; incompatible adapter version');
} Type guard
function hasGetUser(a: unknown): a is { getUser: (...args: unknown[]) => Promise<unknown> } {
return typeof a === 'object' && a !== null && typeof (a as any).getUser === 'function';
} Try / catch
try {
scoped = scopeMicrosoftTeamsEgress(adapter);
} catch (err) {
if (err instanceof TeamsAdapterCompatibilityError && err.message === 'getUser is unavailable') {
logger.error('Adapter lacks getUser; expected by the egress scoper');
}
throw err;
} Prevention
- Keep adapter mocks in tests at full surface (getUser, getIncomingUser, cacheUserContext included).
- Pin adapter dependencies; check the adapter's exported type for getUser after upgrades.
- Run a startup compatibility check that throws before the first Teams activity arrives.
When it happens
Trigger: Invoking scopeMicrosoftTeamsEgress on an adapter object lacking a callable getUser — wrong adapter type, older/newer adapter package where the method was renamed, or an incomplete mock in tests.
Common situations: Adapter package drift after a dependency upgrade; a developer-built adapter subclass that overrides the prototype and drops getUser; passing a generic chat adapter into the Teams-specific egress scoper.
Related errors
- getIncomingUser is unavailable
- ${methodName} is unavailable
- decodeThreadId is unavailable
- openDM is unavailable
- cacheUserContext is unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/062cf2aeade387cb.
Report an issue: GitHub.