paperclipai/paperclip · error · TeamsAdapterCompatibilityError

durable accepted-activity state is unavailable

Error message

durable accepted-activity state is unavailable

What it means

paperclipRecordAcceptedActivity persists verified routing state (serviceUrl, aadObjectId, tenantId, channel context) via the adapter's durable chat state store obtained from teams.chat?.getState(). If that returns null/undefined there is no durable store to write to, and recording an accepted activity would silently lose the routing data Microsoft requires — so the wrapper throws this compatibility error instead.

Source

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

  teams.cacheUserContext = () => {};
  teams.getIncomingUser = async () => null;
  teams.getUser = async () => null;

  teams.paperclipRecordAcceptedActivity = async (activityValue: unknown) => {
    if (!isRecord(activityValue)) return;
    const from = isRecord(activityValue.from) ? activityValue.from : null;
    const conversation = isRecord(activityValue.conversation)
      ? activityValue.conversation
      : null;
    const channelData = isRecord(activityValue.channelData)
      ? activityValue.channelData
      : null;
    const userId =
      typeof from?.id === "string" && from.id.length > 0 ? from.id : null;
    if (!userId) return;
    const state = teams.chat?.getState();
    if (!state) {
      throw new TeamsAdapterCompatibilityError(
        "durable accepted-activity state is unavailable",
      );
    }
    const ttl = TEAMS_ACCEPTED_ACTIVITY_CACHE_TTL_MS;
    const writes: Promise<void>[] = [];
    if (activityValue.serviceUrl !== undefined) {
      writes.push(
        state.set(
          `teams:serviceUrl:${userId}`,
          trustedTeamsServiceUrl(
            activityValue.serviceUrl,
            trustedConfiguredApiUrl,
          ),
          ttl,
        ),
      );
    }
    if (typeof from?.aadObjectId === "string" && from.aadObjectId.length > 0) {

View on GitHub (pinned to 01ad858492)

Solutions

  1. Configure the Teams adapter's chat state (teams.chat with a working getState()) before wiring scopeMicrosoftTeamsEgress.
  2. Upgrade/pin the Teams adapter so the chat state accessor matches TeamsAdapterInternals.
  3. Provide a stateful test double for teams.chat.getState() in unit tests.
  4. Check adapter initialization order — state middleware must be attached before the first activity is processed.

Example fix

// before
const adapter = createTeamsAdapter(); // chat/state middleware not attached
scopeMicrosoftTeamsEgress(adapter);
// after
const adapter = createTeamsAdapter();
adapter.useTeamsChatState(store); // ensures teams.chat.getState() returns a state object
scopeMicrosoftTeamsEgress(adapter);
Defensive patterns

Strategy: try-catch

Validate before calling

const state = adapter.chat?.getState?.();
if (!state) throw new Error('Teams chat state store must be initialized before accepting activities');

Type guard

function hasDurableState(a: unknown): a is { chat: { getState: () => NonNullable<unknown> } } {
  const chat = (a as any)?.chat;
  return !!chat && typeof chat.getState === 'function' && !!chat.getState();
}

Try / catch

try {
  await teams.paperclipRecordAcceptedActivity(activity);
} catch (err) {
  if (err instanceof TeamsAdapterCompatibilityError && err.message.includes('durable accepted-activity state')) {
    logger.error('Teams chat state missing — attach state middleware before processing activities');
  }
  throw err;
}

Prevention

When it happens

Trigger: An accepted Teams activity arrives with a from.id, and teams.chat is undefined or teams.chat.getState() returns a falsy value — e.g. an adapter without chat state middleware configured, or state not yet initialized.

Common situations: Running the Teams adapter without its persistence/state plugin enabled; adapter package versions where chat state access moved to a different accessor; test adapters lacking a chat/state implementation while simulating inbound activities.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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