{"record":{"id":"18c9b09fafb5b194","repo":"paperclipai/paperclip","slug":"file-publication-receipt-capture-was-called-for-a","errorCode":null,"errorMessage":"file publication receipt capture was called for a non-Slack endpoint","messagePattern":"file publication receipt capture was called for a non-Slack endpoint","errorType":"exception","errorClass":"SlackAdapterCompatibilityError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":2488,"sourceCode":"      paperclipDraftControl: control,\n    });\n  }\n\n  /**\n   * Post one Slack file-only publication while durably recording the accepted\n   * upload IDs before the adapter performs its eventually-consistent share\n   * lookup. This specialized receipt scope is deliberately unavailable for\n   * cards, edits, and ordinary text sends; the send still uses Thread.post.\n   */\n  async postSlackFilePublication(\n    threadId: string,\n    message: Parameters<Thread[\"post\"]>[0],\n    onUploadAccepted: (\n      receipt: SlackFileUploadAcceptedReceipt,\n    ) => Promise<void>,\n  ): Promise<{ id: string }> {\n    if (this.provider !== \"slack\") {\n      throw new SlackAdapterCompatibilityError(\n        \"file publication receipt capture was called for a non-Slack endpoint\",\n      );\n    }\n    const slack = this.adapter as unknown as SlackAdapterInternals;\n    if (\n      !slack.paperclipFileUploadReceiptContext ||\n      typeof slack.paperclipResolveFileUploadReceipt !== \"function\"\n    ) {\n      throw new SlackAdapterCompatibilityError(\n        \"file publication receipt capture is unavailable\",\n      );\n    }\n    return await slack.paperclipFileUploadReceiptContext.run(\n      onUploadAccepted,\n      async () => await this.chat.thread(threadId).post(message),\n    );\n  }\n","sourceCodeStart":2470,"sourceCodeEnd":2506,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L2470-L2506","documentation":"postSlackFilePublication captures an upload receipt that only the Slack adapter can record, so the runtime first asserts this.provider === 'slack'. Calling it against any other provider's endpoint would leave the receipt callback unresolvable, so a SlackAdapterCompatibilityError is thrown before any message is sent.","triggerScenarios":"Invoking postSlackFilePublication(threadId, message, onUploadAccepted) on a runtime whose endpoint provider is not 'slack' (e.g. telegram, discord, microsoft-teams).","commonSituations":"Shared send-helper code reused across provider endpoints without checking the provider; misconfigured endpoint mapping that routes a Slack-specific file flow to a Teams or Telegram runtime; tests instantiating a non-Slack adapter but exercising Slack publication code.","solutions":["Guard the call with a provider check (runtime provider === 'slack') and route other providers to their normal Thread.post path.","Fix endpoint/provider configuration so the file publication flow runs against a Slack endpoint.","If generic file publishing is needed for all providers, use the provider-agnostic Thread.post API instead of the Slack-specific receipt path."],"exampleFix":"// before\nawait runtime.postSlackFilePublication(threadId, message, onUploadAccepted);\n\n// after\nif (runtime.provider === \"slack\") {\n  await runtime.postSlackFilePublication(threadId, message, onUploadAccepted);\n} else {\n  await runtime.thread(threadId).post(message);\n}","handlingStrategy":"validation","validationCode":"if (runtime.provider !== \"slack\") throw new Error(\"postSlackFilePublication requires a Slack endpoint\");","typeGuard":"function isSlackRuntime(r: { provider: string }): boolean { return r.provider === \"slack\"; }","tryCatchPattern":"try {\n  await runtime.postSlackFilePublication(threadId, message, onUploadAccepted);\n} catch (err) {\n  if (err instanceof SlackAdapterCompatibilityError) {\n    await runtime.thread(threadId).post(message);\n  } else throw err;\n}","preventionTips":["Route Slack-specific flows through a provider dispatch, never call them from shared send helpers.","Assert provider at flow entry, not deep inside publication logic.","Keep provider-to-flow mapping in configuration so re-provisioned endpoints cannot reach Slack-only code."],"tags":["slack","adapter-compatibility","file-upload","provider-guard"],"backgroundTag":"unsupported-operation","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"}