paperclipai/paperclip · error · TeamsAdapterCompatibilityError

cacheUserContext is unavailable

Error message

cacheUserContext is unavailable

What it means

Continuing the same compatibility gate, the runtime requires adapter.cacheUserContext to be a function; when absent it throws TeamsAdapterCompatibilityError('cacheUserContext is unavailable'). Without it the runtime cannot persist Teams user context across turns and refuses to wire the adapter.

Source

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

 * 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`);
    }
  }
  if (
    typeof teams.app.api.constructor !== "function" ||
    !("http" in teams.app.api)
  ) {
    throw new TeamsAdapterCompatibilityError(
      "the API client constructor or HTTP transport is unavailable",

View on GitHub (pinned to 01ad858492)

Solutions

  1. Bring the Teams adapter package to the version the runtime expects (all required internals present).
  2. Implement cacheUserContext on the custom adapter with the expected signature.
  3. Add cacheUserContext: vi.fn() to test doubles.
  4. After fixing, re-run so the gate proceeds to the remaining checks (getIncomingUser, getUser).

Example fix

// before
const adapter = { app: { api: {} }, decodeThreadId: vi.fn(), openDM: vi.fn() };
// after
const adapter = { app: { api: {} }, decodeThreadId: vi.fn(), openDM: vi.fn(), cacheUserContext: vi.fn() };
Defensive patterns

Strategy: type-guard

Validate before calling

const teams = adapter as unknown as TeamsAdapterInternals;
if (typeof teams.cacheUserContext !== "function") throw new Error("adapter missing cacheUserContext");

Type guard

function supportsCacheUserContext(a: unknown): a is TeamsAdapterInternals {
  return typeof (a as TeamsAdapterInternals)?.cacheUserContext === "function";
}

Try / catch

try {
  wireTeamsAdapter(adapter);
} catch (e) {
  if (e instanceof TeamsAdapterCompatibilityError && e.message.includes("cacheUserContext")) {
    // implement/upgrade so cacheUserContext exists
  }
}

Prevention

When it happens

Trigger: Providing a Teams adapter whose internals have app.api, decodeThreadId, and openDM but lack a cacheUserContext function — typically a version mismatch or an incomplete stub, since the checks run sequentially and this one fails only after the earlier methods passed.

Common situations: Partially upgraded adapter package where some methods were added in one release and others in a later one; custom adapter covering the thread/DM APIs but not user-context caching; mocks extended only as far as the previous failure.

Related errors


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