paperclipai/paperclip · error · TeamsAdapterCompatibilityError
decodeThreadId is unavailable
Error message
decodeThreadId is unavailable
What it means
The Teams adapter compatibility shim inspects internal properties of the installed Teams adapter before wiring it into the chat SDK runtime. If adapter.decodeThreadId is not a function it throws TeamsAdapterCompatibilityError('decodeThreadId is unavailable'), meaning the adapter object does not expose the expected internal API surface.
Source
Thrown at server/src/services/chat-sdk-runtime.ts:1016
* requires replies to target that matching URL. The URL is mutable routing
* state, not conversation identity, so current thread ids omit it. Persist the
* latest verified route under the stable conversation id and scope each
* outbound call to a fresh API client rooted at that route. Legacy thread ids
* that embedded a URL remain readable, but a newer persisted route wins. A
* context-local getter keeps simultaneous conversations isolated without
* forcing unrelated Teams threads through a single network queue.
*/
export function scopeMicrosoftTeamsEgress(
adapter: Adapter,
configuredApiUrl?: string,
enableFileConsent = false,
): 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`);
}
}View on GitHub (pinned to 01ad858492)
Solutions
- Upgrade the Teams adapter package to the version the runtime expects so all internal methods (decodeThreadId, openDM, cacheUserContext, getIncomingUser, getUser) exist.
- Implement decodeThreadId on your custom adapter with the same signature the runtime calls.
- Fix the test double/stub to include a decodeThreadId function (e.g. vi.fn()).
- Check that the object passed as `adapter` is actually the Teams adapter instance, not a wrapper that hides internals.
Example fix
// before: stub missing method
const adapter = { app: { api: {} }, openDM: vi.fn() };
// after
const adapter = { app: { api: {} }, decodeThreadId: vi.fn(), openDM: vi.fn(), cacheUserContext: vi.fn(), getIncomingUser: vi.fn(), getUser: vi.fn() }; Defensive patterns
Strategy: type-guard
Validate before calling
const teams = adapter as unknown as TeamsAdapterInternals;
if (typeof teams.decodeThreadId !== "function") throw new Error("adapter missing decodeThreadId"); Type guard
function supportsDecodeThreadId(a: unknown): a is TeamsAdapterInternals {
return typeof (a as TeamsAdapterInternals)?.decodeThreadId === "function";
} Try / catch
try {
wireTeamsAdapter(adapter);
} catch (e) {
if (e instanceof TeamsAdapterCompatibilityError) {
// upgrade the adapter package to the version matching the runtime
}
} Prevention
- Pin the Teams adapter package version to one known compatible with the runtime.
- Before wiring, feature-check all required internals (decodeThreadId, openDM, cacheUserContext, getIncomingUser, getUser).
- Keep test doubles complete — stub every method the compatibility gate inspects.
- Read adapter release notes when upgrading so internal contract changes are caught early.
When it happens
Trigger: Passing an adapter (or a mocked/stubbed Teams adapter) whose app internals are set but which lacks a decodeThreadId method — e.g. an adapter package version predating that method, or a partial custom implementation.
Common situations: Upgrading or downgrading the Teams adapter package so internals drifted from what the runtime expects; a hand-rolled adapter missing decodeThreadId; a test double that stubs only some methods.
Related errors
- openDM is unavailable
- cacheUserContext is unavailable
- getIncomingUser is unavailable
- getUser is unavailable
- ${methodName} is unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/4a2221b4f11ea4a6.
Report an issue: GitHub.