{"record":{"id":"1e4c096f313749a0","repo":"paperclipai/paperclip","slug":"file-publication-receipt-lookup-is-unavailable","errorCode":null,"errorMessage":"file publication receipt lookup is unavailable","messagePattern":"file publication receipt lookup is unavailable","errorType":"exception","errorClass":"SlackAdapterCompatibilityError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":2519,"sourceCode":"    return await slack.paperclipFileUploadReceiptContext.run(\n      onUploadAccepted,\n      async () => await this.chat.thread(threadId).post(message),\n    );\n  }\n\n  /** Resolve a previously accepted Slack upload using metadata reads only. */\n  async resolveSlackFileUploadReceipt(\n    threadId: string,\n    fileIds: string[],\n  ): Promise<string | null> {\n    if (this.provider !== \"slack\") {\n      throw new SlackAdapterCompatibilityError(\n        \"file publication receipt lookup was called for a non-Slack endpoint\",\n      );\n    }\n    const slack = this.adapter as unknown as SlackAdapterInternals;\n    if (typeof slack.paperclipResolveFileUploadReceipt !== \"function\") {\n      throw new SlackAdapterCompatibilityError(\n        \"file publication receipt lookup is unavailable\",\n      );\n    }\n    return await slack.paperclipResolveFileUploadReceipt.call(\n      this.adapter,\n      fileIds,\n      threadId,\n    );\n  }\n\n  /**\n   * Persist a Teams activity's authenticated reply route only after the\n   * control plane has accepted the callback under the current runtime and\n   * credential generation. The route is intentionally separate from the\n   * durable provider thread id because Microsoft can move a conversation\n   * between regional Bot Connector service URLs.\n   */\n  async recordMicrosoftTeamsRoute(","sourceCodeStart":2501,"sourceCodeEnd":2537,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L2501-L2537","documentation":"Even on a Slack endpoint, the runtime needs the adapter's internal paperclipResolveFileUploadReceipt function to perform the metadata-only receipt lookup. If the wired Slack adapter does not define it, a SlackAdapterCompatibilityError is thrown because receipt resolution cannot be served by an adapter lacking that capability.","triggerScenarios":"Calling resolveSlackFileUploadReceipt against a Slack runtime whose adapter instance lacks paperclipResolveFileUploadReceipt — typically an outdated adapter version or a partial adapter/test double.","commonSituations":"Adapter package pinned before the file-receipt lookup feature landed; custom Slack adapters implementing upload but not receipt resolution; tests stubbing the adapter with only a subset of internals.","solutions":["Upgrade the Slack adapter to a version exposing paperclipResolveFileUploadReceipt.","Feature-detect the function before calling and treat the receipt as unresolvable (return null) instead of throwing.","Fix test doubles to include paperclipResolveFileUploadReceipt."],"exampleFix":"// before\nconst path = await runtime.resolveSlackFileUploadReceipt(threadId, fileIds);\n\n// after\nconst slack = runtime.getProviderAdapter() as {\n  paperclipResolveFileUploadReceipt?: unknown;\n};\nconst path = typeof slack.paperclipResolveFileUploadReceipt === \"function\"\n  ? await runtime.resolveSlackFileUploadReceipt(threadId, fileIds)\n  : null;","handlingStrategy":"type-guard","validationCode":"const slack = runtime.getProviderAdapter() as Record<string, unknown>;\nif (typeof slack.paperclipResolveFileUploadReceipt !== \"function\") return null;","typeGuard":"function supportsReceiptResolution(a: unknown): a is { paperclipResolveFileUploadReceipt: (fileIds: string[], threadId: string) => Promise<string | null> } {\n  return typeof a === \"object\" && a !== null && typeof (a as any).paperclipResolveFileUploadReceipt === \"function\";\n}","tryCatchPattern":"try {\n  return await runtime.resolveSlackFileUploadReceipt(threadId, fileIds);\n} catch (err) {\n  if (err instanceof SlackAdapterCompatibilityError && err.message.includes(\"lookup is unavailable\")) return null;\n  throw err;\n}","preventionTips":["Upgrade/pin the Slack adapter to one exposing paperclipResolveFileUploadReceipt.","Feature-detect the hook and degrade gracefully to null instead of crashing lookups.","Add an adapter capability smoke test in CI."],"tags":["slack","adapter-compatibility","file-upload","missing-capability"],"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"}