paperclipai/paperclip · error · TeamsAdapterCompatibilityError
invalid file-card shape
Error message
invalid file-card shape
What it means
paperclipSendFileCard validates its input with parseTeamsFileConsentCard (for kind 'consent') or parseTeamsUploadedFileCard (for kind 'file_info'). If the kind is neither, or the input fails the parser's shape requirements, the card cannot be turned into a valid Teams attachment, so this compatibility error is thrown before any network call.
Source
Thrown at server/src/services/chat-sdk-runtime.ts:1234
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 ||
decoded.conversationId.length > 1024 ||
/[\x00-\x20\x7f]/.test(decoded.conversationId) ||
/;messageid=/i.test(decoded.conversationId)
) {
throw new TeamsServiceUrlValidationError(
"Teams file cards require an exact personal conversation",
);
}
return await withThreadServiceUrl(
threadId,
async () => {
let result: unknown;View on GitHub (pinned to 01ad858492)
Solutions
- Validate the kind argument is exactly 'consent' or 'file_info' before calling.
- Run the input through the same parser (parseTeamsFileConsentCard/parseTeamsUploadedFileCard) at the call site to see which required field is missing.
- Fix the upstream producer so the card payload includes all required fields (name, uploadUrl/acceptContext for consent; fileId/name/contentUrl for file_info).
- Add a unit test feeding representative payloads into paperclipSendFileCard to catch shape drift.
Example fix
// before
await teams.paperclipSendFileCard(threadId, 'consent', { foo: 1 }); // invalid shape
// after
await teams.paperclipSendFileCard(threadId, 'consent', {
name: 'report.pdf',
uploadUrl: uploadCtx.uploadUrl,
contentUrl: uploadCtx.contentUrl,
acceptContext: { threadId }
}); Defensive patterns
Strategy: validation
Validate before calling
const card = kind === 'consent' ? parseTeamsFileConsentCard(input) : kind === 'file_info' ? parseTeamsUploadedFileCard(input) : null;
if (!card) throw new Error(`Invalid ${kind} file-card payload`); Type guard
function isFileCardKind(k: string): k is 'consent' | 'file_info' {
return k === 'consent' || k === 'file_info';
} Try / catch
try {
await teams.paperclipSendFileCard(threadId, kind, input);
} catch (err) {
if (err instanceof TeamsAdapterCompatibilityError && err.message === 'invalid file-card shape') {
logger.error(`Rejected ${kind} file card payload: ${JSON.stringify(input).slice(0, 200)}`);
}
throw err;
} Prevention
- Validate kind and payload shape at the producer boundary before invoking paperclipSendFileCard.
- Share the same parser functions (parseTeamsFileConsentCard/parseTeamsUploadedFileCard) between producer and sender so schemas cannot drift.
- Add snapshot/unit tests covering both card kinds and a rejection case for unknown kinds.
When it happens
Trigger: Calling teams.paperclipSendFileCard(threadId, kind, input) with kind not in {'consent','file_info'}, or input missing fields the parsers require (e.g. no name/acceptContext for consent, no fileId/name for file_info), or input being null/undefined.
Common situations: A typo'd kind string ('consentCard' instead of 'consent'); a caller passing the raw upload result instead of the parsed card payload; schema drift after changing the upstream file metadata producer so required fields disappear.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Teams destination is missing its conversation identity
- Teams file destination is missing its verified route
- file-consent App hooks are unavailable
- Teams file cards require an exact personal conversation
- file-consent requires a configured tenant and App hook
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/4e5e2aa3444f2956.
Report an issue: GitHub.