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
- Configure the Teams adapter's chat state (teams.chat with a working getState()) before wiring scopeMicrosoftTeamsEgress.
- Upgrade/pin the Teams adapter so the chat state accessor matches TeamsAdapterInternals.
- Provide a stateful test double for teams.chat.getState() in unit tests.
- 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
- Attach the adapter's chat/state middleware during bootstrap, before any inbound activity can be accepted.
- In tests, supply a teams.chat double whose getState returns a real in-memory state object.
- Monitor adapter upgrades for changes to the chat/state accessor shape.
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
- decodeThreadId is unavailable
- openDM is unavailable
- cacheUserContext is unavailable
- getIncomingUser is unavailable
- getUser is unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/f0883398115a8186.
Report an issue: GitHub.