Skip to content

fix(bluebubbles): accept updated-message events carrying attachments#66120

Closed
coletebou wants to merge 1 commit intoopenclaw:mainfrom
coletebou:fix/bb-attachment-update-v3
Closed

fix(bluebubbles): accept updated-message events carrying attachments#66120
coletebou wants to merge 1 commit intoopenclaw:mainfrom
coletebou:fix/bb-attachment-update-v3

Conversation

@coletebou
Copy link
Copy Markdown

Summary

BlueBubbles fires new-message first (text only), then updated-message ~2-3s later once attachment data is ready. The webhook filter unconditionally discards updated-message events that are not reactions, silently dropping all inbound images, PDFs, and files.

Lets updated-message events through when data.attachments is non-empty. Text is preserved (not stripped) so that mention gating in group chats works correctly.

Supersedes #66105 and #63983.

Changes

  • extensions/bluebubbles/src/monitor.ts:
    • Detect attachment-bearing updated-message via asRecord(payload.data)?.attachments
    • Pass these events through the event type filter alongside reactions

Known limitation

For text+attachment sends, the text body is delivered twice — once from new-message and once from the updated-message that carries the attachment. The 500ms debounce window is shorter than the ~2-3s BB delay, so they aren't coalesced. A messageId-based seen-set in the debouncer would close this gap but is left as a follow-up to keep this fix minimal. Dropping attachments (the current behavior) is a worse outcome than a duplicate text line.

Test plan

  • Send an image via iMessage to a BB-connected agent — confirm the image is received
  • Send text + image — confirm both arrive (text may appear twice)
  • Verify updated-message events without attachments are still filtered out
  • Verify mention gating works in group chats with attachments
  • Verify reactions still work normally

BlueBubbles fires new-message first (text only), then updated-message
~2-3s later once attachment data is ready. The webhook filter
unconditionally discards updated-message events that are not reactions,
silently dropping all inbound images, PDFs, and files.

Let updated-message events through when data.attachments is non-empty.
Text is preserved (not stripped) so that mention gating in group chats
continues to work correctly. For text+attachment sends this means the
text body is delivered twice (once from new-message, once from
updated-message); a messageId-based seen-set in the debouncer would
close this gap but is left as a follow-up to keep this fix minimal.
@openclaw-barnacle openclaw-barnacle Bot added channel: bluebubbles Channel integration: bluebubbles size: XS labels Apr 13, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 348aba1baa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +257 to +259
const dataAttachments = asRecord(payload.data)?.attachments;
const isAttachmentUpdate =
eventType === "updated-message" && Array.isArray(dataAttachments) && dataAttachments.length > 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Detect attachment updates from parsed message, not raw data

The new isAttachmentUpdate gate only checks asRecord(payload.data)?.attachments, but this webhook path already supports non-record wrappers (for example array- or string-wrapped payloads) via extractMessagePayload in normalizeWebhookMessage. For updated-message events where attachments are present but payload.data is not a plain object, isAttachmentUpdate stays false and the event is still dropped by the updated-message/!reaction filter, so inbound attachments remain silently lost in those supported payload shapes.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 13, 2026

Greptile Summary

Fixes silent attachment loss in the BlueBubbles webhook handler by allowing updated-message events through the event-type filter when payload.data.attachments is non-empty. The fix is minimal and correct: the attachment check is scoped to data.attachments to match the exact message container path used by normalizeWebhookMessage, fromMe messages are already returned early in processMessage, and attachment-only bodies produce a non-empty rawBody via buildMessagePlaceholder. The acknowledged duplicate-text side effect (text body delivered twice for text+attachment sends) is a reasonable trade-off deferred to a follow-up.

Confidence Score: 5/5

Safe to merge; all findings are P2 style/test suggestions that do not block correctness.

The logic change is small and well-reasoned: the isAttachmentUpdate guard correctly matches the payload structure consumed by normalizeWebhookMessage, fromMe short-circuit in processMessage prevents self-message loops, and attachment-only bodies are handled by the existing placeholder path. The only findings are a slightly stale log string and missing automated test cases — neither affects runtime correctness.

extensions/bluebubbles/src/monitor.ts — minor log string and no test coverage for the new updated-message + attachments path.

Comments Outside Diff (1)

  1. extensions/bluebubbles/src/monitor.ts, line 269-276 (link)

    P2 Stale log message after filter expansion

    The log still reads without reaction, but updated-message events are now also discarded when they have no attachments. A reader debugging a dropped event might incorrectly conclude it was reaction-related.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/bluebubbles/src/monitor.ts
    Line: 269-276
    
    Comment:
    **Stale log message after filter expansion**
    
    The log still reads `without reaction`, but `updated-message` events are now also discarded when they have no attachments. A reader debugging a dropped event might incorrectly conclude it was reaction-related.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Codex Fix in Claude Code

Fix All in Codex Fix All in Claude Code

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/bluebubbles/src/monitor.ts
Line: 269-276

Comment:
**Stale log message after filter expansion**

The log still reads `without reaction`, but `updated-message` events are now also discarded when they have no attachments. A reader debugging a dropped event might incorrectly conclude it was reaction-related.

```suggestion
        logVerbose(
            firstTarget.core,
            firstTarget.runtime,
            `webhook ignored ${eventType || "event"} without reaction or attachments`,
          );
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/bluebubbles/src/monitor.ts
Line: 251-259

Comment:
**No automated test coverage for the new path**

The fix introduces a meaningful new branch — `updated-message` events carrying `data.attachments` now pass through the filter — but `monitor.test.ts` has no test cases for this scenario. Given that the old behavior silently dropped attachments and `updated-message` filtering is easy to regress, a few focused tests would be valuable: one asserting that `updated-message` with non-empty `data.attachments` is accepted, one asserting that `updated-message` without attachments is still discarded, and one confirming `new-message` with attachments continues to work normally.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(bluebubbles): accept updated-message..." | Re-trigger Greptile

Comment on lines +251 to +259
// Allow updated-message events through when they carry attachments.
// BB fires new-message (text only), then updated-message ~2-3s later once
// attachment data is ready. Without this, inbound images/PDFs/files are
// silently dropped. Only check data.attachments (normalizeWebhookMessage
// requires a message container in payload.data, so root-only attachment
// payloads would pass the filter but fail normalization).
const dataAttachments = asRecord(payload.data)?.attachments;
const isAttachmentUpdate =
eventType === "updated-message" && Array.isArray(dataAttachments) && dataAttachments.length > 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No automated test coverage for the new path

The fix introduces a meaningful new branch — updated-message events carrying data.attachments now pass through the filter — but monitor.test.ts has no test cases for this scenario. Given that the old behavior silently dropped attachments and updated-message filtering is easy to regress, a few focused tests would be valuable: one asserting that updated-message with non-empty data.attachments is accepted, one asserting that updated-message without attachments is still discarded, and one confirming new-message with attachments continues to work normally.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/bluebubbles/src/monitor.ts
Line: 251-259

Comment:
**No automated test coverage for the new path**

The fix introduces a meaningful new branch — `updated-message` events carrying `data.attachments` now pass through the filter — but `monitor.test.ts` has no test cases for this scenario. Given that the old behavior silently dropped attachments and `updated-message` filtering is easy to regress, a few focused tests would be valuable: one asserting that `updated-message` with non-empty `data.attachments` is accepted, one asserting that `updated-message` without attachments is still discarded, and one confirming `new-message` with attachments continues to work normally.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex Fix in Claude Code

@omarshahine
Copy link
Copy Markdown
Contributor

Superseded by #67510 (merged 2026-04-16), which explicitly lists this PR as subsumed. #67510's fix #2 accepts updated-message events carrying attachments, plus three related fixes for inbound media on Node 22+. Thanks for the patch — closing in favor of the merged work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: bluebubbles Channel integration: bluebubbles size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants