Skip to content

Plugin/extension channel delivery failures are silent and unrecoverable #29126

@nohat

Description

@nohat

Problem

The current plugin outbound adapter contract (sendText / sendMedia / sendDocument) is fire-and-forget. When delivery to a plugin channel fails (network error, API rate limit, transient outage), the message is lost with no retry, no persistent error record, and no notification to the user or operator.

Built-in channels (Telegram, WhatsApp, etc.) have their own ad-hoc retry/recovery logic, but this is not available to plugin channels through the adapter contract. Each plugin author would need to implement their own retry and crash recovery — and in practice, none do.

Specific pain

  • MS Teams: If the Teams API returns a transient 429 or 503 during delivery, the reply is lost. The user sees the bot "read" their message but the bot never responds.
  • Matrix / Zalo / other extensions: Same — any transient failure during sendText/sendMedia silently drops the message.
  • Gateway crash during delivery: If the process dies between generating the reply and completing sendText, the reply is gone. There is no mechanism to detect or replay the failed delivery on restart.
  • No operator visibility: Delivery failures in plugins are caught and logged but not queryable. An operator cannot answer "which plugin messages failed to deliver today?"

Current adapter contract

sendText(to: string, text: string, options?: {...}): Promise<void>
sendMedia(to: string, media: {...}): Promise<void>

These are void-returning — there is no way for the core delivery infrastructure to track the outcome, retry on failure, or persist the payload for crash recovery.

Expected behavior

The adapter contract should support a delivery method that the core infrastructure can call with retry/persistence semantics, giving plugin channels the same durability guarantees as built-in channels. Delivery attempts and their outcomes should be recorded in a queryable store.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions