paperclipai/paperclip · error · TeamsAdapterCompatibilityError
file-consent App hooks are unavailable
Error message
file-consent App hooks are unavailable
What it means
File-consent support (enableFileConsent = true) requires the Teams App object to expose send and on hooks: the wrapper registers handlers via app.on and delivers provider-native file cards via app.send inside the routed ALS scope. If either hook is missing, the adapter surface is incompatible with the file-consent feature and this compatibility error is thrown at wiring time.
Source
Thrown at server/src/services/chat-sdk-runtime.ts:1222
persistedServiceUrl == null &&
decoded.serviceUrl == null
) {
throw new TeamsServiceUrlValidationError(
"Teams file destination is missing its verified route",
);
}
return await withServiceUrl(
persistedServiceUrl ?? decoded.serviceUrl ?? defaultApi.serviceUrl,
operation,
);
};
if (enableFileConsent) {
if (
typeof teams.app.send !== "function" ||
typeof teams.app.on !== "function"
) {
throw new TeamsAdapterCompatibilityError(
"file-consent App hooks are unavailable",
);
}
teams.paperclipSendFileCard = async (threadId, kind, input) => {
const card =
kind === "consent"
? parseTeamsFileConsentCard(input)
: kind === "file_info"
? parseTeamsUploadedFileCard(input)
: null;
if (!card)
throw new TeamsAdapterCompatibilityError("invalid file-card shape");
const decoded = teams.decodeThreadId!(threadId);
// Never infer personal scope from a missing type or conversation prefix.
if (
decoded.conversationType !== "personal" ||
typeof decoded.conversationId !== "string" ||
!decoded.conversationId ||View on GitHub (pinned to 01ad858492)
Solutions
- Use the full Teams adapter App object that implements send and on.
- Enable file consent only with an adapter version known to support App hooks; otherwise pass enableFileConsent = false.
- Extend test doubles with send: async () => {} and on: () => {} stubs.
- Confirm you are passing the app object, not app.api, into the wrapper's expectations.
Example fix
// before
scopeMicrosoftTeamsEgress(adapter, apiUrl, true); // app lacks send/on
// after
// either stub the hooks in tests
app.send = async () => ({});
app.on = () => {};
scopeMicrosoftTeamsEgress(adapter, apiUrl, true);
// or disable the feature
scopeMicrosoftTeamsEgress(adapter, apiUrl, false); Defensive patterns
Strategy: validation
Validate before calling
if (enableFileConsent && (typeof adapter.app?.send !== 'function' || typeof adapter.app?.on !== 'function')) {
throw new Error('File consent requires a Teams App with send and on hooks');
} Type guard
function supportsFileConsentHooks(app: unknown): app is { send: Function; on: Function } {
return typeof app === 'object' && app !== null && typeof (app as any).send === 'function' && typeof (app as any).on === 'function';
} Try / catch
try {
scoped = scopeMicrosoftTeamsEgress(adapter, apiUrl, enableFileConsent);
} catch (err) {
if (err instanceof TeamsAdapterCompatibilityError && err.message.includes('file-consent App hooks')) {
logger.error('File consent enabled but the adapter App lacks send/on — upgrade adapter or disable file consent');
}
throw err;
} Prevention
- Gate enableFileConsent on an adapter capability check rather than config alone.
- Keep test app doubles equipped with send/on stubs.
- Verify adapter version supports App-level hooks before shipping file-consent features.
When it happens
Trigger: Calling scopeMicrosoftTeamsEgress(adapter, configuredApiUrl, true) where typeof teams.app.send !== 'function' or typeof teams.app.on !== 'function' — e.g. a minimal/mocked app object, or an adapter build that omits the App event hooks.
Common situations: Enabling file consent in tests with a partial app mock; an older adapter package whose App object lacked send/on under those names; accidentally passing app.api (the client) where the app object is expected.
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/3ea950b4b070f72e.
Report an issue: GitHub.