{"record":{"id":"062cf2aeade387cb","repo":"paperclipai/paperclip","slug":"getuser-is-unavailable","errorCode":null,"errorMessage":"getUser is unavailable","messagePattern":"getUser is unavailable","errorType":"exception","errorClass":"TeamsAdapterCompatibilityError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":1028,"sourceCode":"): Adapter {\n  const teams = adapter as unknown as TeamsAdapterInternals;\n  if (!teams.app?.api) {\n    throw new TeamsAdapterCompatibilityError(\"app.api is unavailable\");\n  }\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\",","sourceCodeStart":1010,"sourceCodeEnd":1046,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L1010-L1046","documentation":"As part of the same compatibility audit, scopeMicrosoftTeamsEgress requires the Teams adapter to expose getUser, because it replaces it with a stub (async () => null) to keep pre-admission Teams events inert. If the method is absent the adapter is considered incompatible and the wrapper throws instead of proceeding with partially-stubbed behavior.","triggerScenarios":"Invoking scopeMicrosoftTeamsEgress on an adapter object lacking a callable getUser — wrong adapter type, older/newer adapter package where the method was renamed, or an incomplete mock in tests.","commonSituations":"Adapter package drift after a dependency upgrade; a developer-built adapter subclass that overrides the prototype and drops getUser; passing a generic chat adapter into the Teams-specific egress scoper.","solutions":["Confirm typeof adapter.getUser === 'function' before calling scopeMicrosoftTeamsEgress.","Restore or upgrade the official Teams adapter so getUser exists.","In tests, provide a getUser stub (async () => null is sufficient) on the mock adapter.","Check that subclassing or proxying the adapter has not shadowed or removed the method."],"exampleFix":"// before\nconst mock = { app, decodeThreadId, openDM };\nscopeMicrosoftTeamsEgress(mock as unknown as Adapter);\n// after\nconst mock = { app, decodeThreadId, openDM, getUser: async () => null, getIncomingUser: async () => null, cacheUserContext: () => {} };\nscopeMicrosoftTeamsEgress(mock as unknown as Adapter);","handlingStrategy":"validation","validationCode":"if (typeof adapter.getUser !== 'function') {\n  throw new Error('Teams adapter missing getUser; incompatible adapter version');\n}","typeGuard":"function hasGetUser(a: unknown): a is { getUser: (...args: unknown[]) => Promise<unknown> } {\n  return typeof a === 'object' && a !== null && typeof (a as any).getUser === 'function';\n}","tryCatchPattern":"try {\n  scoped = scopeMicrosoftTeamsEgress(adapter);\n} catch (err) {\n  if (err instanceof TeamsAdapterCompatibilityError && err.message === 'getUser is unavailable') {\n    logger.error('Adapter lacks getUser; expected by the egress scoper');\n  }\n  throw err;\n}","preventionTips":["Keep adapter mocks in tests at full surface (getUser, getIncomingUser, cacheUserContext included).","Pin adapter dependencies; check the adapter's exported type for getUser after upgrades.","Run a startup compatibility check that throws before the first Teams activity arrives."],"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-14T00:17:10.932Z"}