paperclipai/paperclip · error

Teams inline image download unavailable

Error message

Teams inline image download unavailable

What it means

fetchTeamsInlineImage downloads a Teams message inline image via a per-attachment fetcher that was registered when the attachment was admitted. If no fetcher exists for the given attachment, or the AbortSignal is already aborted, it throws 'Teams inline image download unavailable'. The download capability is intentionally ephemeral: fetchers exist only for attachments seen during inbound admission.

Source

Thrown at server/src/services/chat-sdk-runtime.ts:2825

      throw Object.assign(
        new Error("Telegram private response runtime unavailable"),
        { code: "CHAT_PROVIDER_PRETRANSPORT_REJECTED" },
      );
    }
    return sendTelegramCallbackNotice(
      { receipt, text, botToken: this.telegramEphemeralBotToken },
      fetchImpl,
    );
  }

  /** Only attachments reconstructed by this runtime can use the batch budget. */
  async fetchTeamsInlineImage(
    attachment: Attachment,
    signal: AbortSignal,
  ): Promise<Buffer> {
    const fetcher = this.teamsInlineImageFetchers.get(attachment);
    if (!fetcher || signal.aborted)
      throw new Error("Teams inline image download unavailable");
    return await fetcher(signal);
  }

  /** Called only after current inbound admission; installation App authority only. */
  async resolveGitHubAttachmentComment(
    request: GitHubAttachmentCommentRequest,
    signal: AbortSignal,
  ): Promise<unknown> {
    if (!this.githubAttachmentAppAuthority)
      throw new GitHubAttachmentUnavailableError(
        "github_attachment_canonical_authority_unavailable",
      );
    if (!isGitHubAttachmentCommentRequest(request))
      throw new GitHubAttachmentUnavailableError(
        "github_attachment_source_mismatch",
      );
    try {
      signal.throwIfAborted();

View on GitHub (pinned to 01ad858492)

Solutions

  1. Download the inline image during/soon after inbound admission while the registered fetcher is still alive
  2. Pass the exact same Attachment object reference produced by admission (not a cloned/deserialized copy)
  3. Check signal.aborted before calling and create a fresh AbortController for a new attempt
  4. If the runtime was replaced, re-admit the message or obtain a new download handle

Example fix

// before
const buf = await runtime.fetchTeamsInlineImage(clonedAttachment, signal);
// after
if (!signal.aborted) {
  const buf = await runtime.fetchTeamsInlineImage(originalAttachment, signal);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (signal.aborted || !runtime.hasTeamsInlineImageFetcher(attachment)) return null;

Try / catch

try { return await runtime.fetchTeamsInlineImage(attachment, signal); } catch { return placeholderBuffer; }

Prevention

When it happens

Trigger: Fetching an attachment that was never registered in this.teamsInlineImageFetchers (e.g. attachment data reconstructed or deserialized after admission, so the WeakMap/get lookup misses), or calling with an already-aborted AbortSignal.

Common situations: Re-hydrating an attachment object from DB/JSON so it no longer matches the original key; delayed download long after the inbound message was processed; caller cancels the request before invoking the fetch; runtime replaced and fetcher map cleared.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/37bfd88025077bf2. Report an issue: GitHub.