{"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":1032,"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":1014,"sourceCodeEnd":1050,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L1014-L1050","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":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}