{"record":{"id":"a8fd8087d6c34967","repo":"paperclipai/paperclip","slug":"methodname-is-unavailable","errorCode":null,"errorMessage":"${methodName} is unavailable","messagePattern":"(.+?) is unavailable","errorType":"exception","errorClass":"TeamsAdapterCompatibilityError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":1049,"sourceCode":"  }\n  if (typeof teams.decodeThreadId !== \"function\") {\n    throw new TeamsAdapterCompatibilityError(\"decodeThreadId is unavailable\");\n  }\n  if (typeof teams.openDM !== \"function\") {\n    throw new TeamsAdapterCompatibilityError(\"openDM is unavailable\");\n  }\n  if (typeof teams.cacheUserContext !== \"function\") {\n    throw new TeamsAdapterCompatibilityError(\"cacheUserContext is unavailable\");\n  }\n  if (typeof teams.getIncomingUser !== \"function\") {\n    throw new TeamsAdapterCompatibilityError(\"getIncomingUser is unavailable\");\n  }\n  if (typeof teams.getUser !== \"function\") {\n    throw new TeamsAdapterCompatibilityError(\"getUser is unavailable\");\n  }\n  for (const methodName of TEAMS_THREAD_SCOPED_METHODS) {\n    if (typeof teams[methodName] !== \"function\") {\n      throw new TeamsAdapterCompatibilityError(`${methodName} is unavailable`);\n    }\n  }\n  if (\n    typeof teams.app.api.constructor !== \"function\" ||\n    !(\"http\" in teams.app.api)\n  ) {\n    throw new TeamsAdapterCompatibilityError(\n      \"the API client constructor or HTTP transport is unavailable\",\n    );\n  }\n  const apiDescriptor = Object.getOwnPropertyDescriptor(teams.app, \"api\");\n  if (apiDescriptor && apiDescriptor.configurable === false) {\n    throw new TeamsAdapterCompatibilityError(\n      \"app.api cannot be scoped per asynchronous conversation\",\n    );\n  }\n  const trustedConfiguredApiUrl = configuredApiUrl\n    ? normalizedTeamsServiceUrl(configuredApiUrl)","sourceCodeStart":1031,"sourceCodeEnd":1067,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/chat-sdk-runtime.ts#L1031-L1067","documentation":"scopeMicrosoftTeamsEgress iterates TEAMS_THREAD_SCOPED_METHODS (the adapter's per-thread operations) and asserts each is a function. Thread-scoped methods must all exist because the wrapper re-routes them through withThreadServiceUrl to scope outbound calls to the conversation's verified service URL. A missing method means the wrapper cannot safely proxy the full thread surface, so it throws.","triggerScenarios":"An adapter object passed to scopeMicrosoftTeamsEgress is missing at least one method listed in TEAMS_THREAD_SCOPED_METHODS; the thrown message names the specific method (e.g. 'postActivity is unavailable').","commonSituations":"Adapter version mismatch after an upgrade; incomplete test doubles; a custom adapter that implements most but not all thread-scoped methods; tree-shaking or build config dropping prototype methods.","solutions":["Read the thrown message to identify which method is missing and check TEAMS_THREAD_SCOPED_METHODS for the full required list.","Use the official, current Teams adapter implementation rather than a partial reimplementation.","Update your test mock to implement every thread-scoped method as a function.","Check the adapter's prototype chain — methods defined only on a class prototype can be lost if the object was spread ({...adapter})."],"exampleFix":"// before (spread drops prototype methods)\nconst partial = { ...createTeamsAdapter() };\nscopeMicrosoftTeamsEgress(partial);\n// after\nconst adapter = createTeamsAdapter(); // keep prototype intact\nscopeMicrosoftTeamsEgress(adapter);","handlingStrategy":"validation","validationCode":"const required = TEAMS_THREAD_SCOPED_METHODS;\nconst missing = required.filter((m) => typeof (adapter as any)[m] !== 'function');\nif (missing.length) throw new Error(`Teams adapter missing thread-scoped methods: ${missing.join(', ')}`);","typeGuard":null,"tryCatchPattern":"try {\n  scoped = scopeMicrosoftTeamsEgress(adapter);\n} catch (err) {\n  if (err instanceof TeamsAdapterCompatibilityError && err.message.endsWith('is unavailable')) {\n    logger.error(`Thread-scoped method missing on Teams adapter: ${err.message}`);\n  }\n  throw err;\n}","preventionTips":["Use the official adapter implementation rather than reimplementing subsets of its API.","Avoid object spreads that drop class-prototype methods ({...adapter}).","Keep a test that iterates TEAMS_THREAD_SCOPED_METHODS against the adapter instance."],"tags":["teams","adapter-compatibility","runtime-check"],"backgroundTag":"method-not-implemented","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}