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

  1. Upgrade the Teams adapter package to the version the runtime expects so all internal methods (decodeThreadId, openDM, cacheUserContext, getIncomingUser, getUser) exist.
  2. Implement decodeThreadId on your custom adapter with the same signature the runtime calls.
  3. Fix the test double/stub to include a decodeThreadId function (e.g. vi.fn()).
  4. 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

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


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