iachat/app/services
Muhsin Keloth efc3b5e7d4
fix: Handle Instagram API error codes properly in message processing (#13002)
### Problem

Instagram webhook processing was failing with:

> TypeError: no implicit conversion of String into Integer

This occurred when handling **echo messages** (outgoing messages) that:

* Contained `unsupported_type` attachments, and
* Were sent to a recipient user that could **not** be fetched via the
Instagram API.

In these cases, the webhook job crashed while trying to create or find
the contact for the recipient.

### Root Cause

The Instagram message service does not correctly handle Instagram API
error code **100**:

> "Object with ID does not exist, cannot be loaded due to missing
permissions, or does not support this operation"

When this error occurred during `fetch_instagram_user`:

1. The method fell through to exception tracking without an explicit
return.
2. `ChatwootExceptionTracker.capture_exception` returned `true`.
3. As a result, `fetch_instagram_user` effectively returned `true`
instead of a hash or empty hash.
4. `ensure_contact` then called `find_or_create_contact(true)` because
`true.present?` is `true`.
5. `find_or_create_contact` crashed when it tried to access
`true['id']`.

So the chain was:

```txt
fetch_instagram_user -> returns true
ensure_contact -> find_or_create_contact(true)
find_or_create_contact -> true['id'] -> TypeError
```

**Example Webhook Payload**

```
{
  "object": "instagram",
  "entry": [{
    "time": 1764822592663,
    "id": "17841454414819988",
    "messaging": [{
      "sender": { "id": "17841454414819988" },     // Business account
      "recipient": { "id": "1170166904857608" },   // User that can't be fetched
      "timestamp": 1764822591874,
      "message": {
        "attachments": [{
          "type": "unsupported_type",
          "payload": { "url": "https://..." }
        }],
        "is_echo": true
      }
    }]
  }]
}
```

**Corresponding Instagram API error:**

```
{
  "error": {
    "message": "The requested user cannot be found.",
    "type": "IGApiException",
    "code": 100,
    "error_subcode": 2534014
  }
}
```

**Debug Logs (Before Fix)**

```
[InstagramUserFetchError]: Unsupported get request. Object with ID '17841454414819988' does not exist... 100
[DEBUG] result: true
[DEBUG] result.present?: true
[DEBUG] find_or_create_contact called
[DEBUG] user: true
[DEBUG] Invalid user parameter - expected hash with id, got TrueClass: true
```

### Solution

### 1\. Handle Error Code 100 Explicitly

We now treat Instagram API error code **100** as a valid case for
creating an “unknown” contact, similar to how we already handle error
code `9010`:

```
# Handle error code 100: Object doesn't exist or missing permissions
# This typically occurs when trying to fetch a user that doesn't exist
# or has privacy restrictions. We can safely create an unknown contact.
return unknown_user(ig_scope_id) if error_code == 100
```

This ensures:

* `fetch_instagram_user` returns a valid hash for unknown users.
* `ensure_contact` can proceed safely without crashing.

### 2\. Prevent Exception Tracker Results from Leaking Through

For any **unhandled** error codes, we now explicitly return an empty
hash after logging the exception:

```
exception = StandardError.new(
  "#{error_message} (Code: #{error_code}, IG Scope ID: #{ig_scope_id})"
)
ChatwootExceptionTracker.new(exception, account: @inbox.account).capture_exception

# Explicitly return empty hash for any unhandled error codes
# This prevents the exception tracker result (true/false) from being returned.
{}
```

This guarantees that `fetch_instagram_user` always returns either:

* A valid user hash,
* An “unknown” user hash
* An empty hash
Fixes
https://linear.app/chatwoot/issue/CW-6068/typeerror-no-implicit-conversion-of-string-into-integer-typeerror
2025-12-04 18:53:50 +05:30
..
account fix: account email validation during signup (#11307) 2025-05-20 20:45:39 -07:00
auto_assignment feat: Assignment service (v2) (#12320) 2025-11-17 10:08:25 +05:30
automation_rules feat: Add support for labels in automations (#11658) 2025-09-18 14:17:54 +05:30
base chore: Add cache to improve widget performance (#11163) 2025-03-24 16:04:49 -07:00
contacts feat: outbound voice call essentials (#12782) 2025-11-24 17:47:00 -08:00
conversations feat: APIs to assign agents_bots as assignee in conversations (#12836) 2025-11-18 18:20:58 -08:00
crm feat: save timezone from leadsquared API (#11583) 2025-05-28 09:46:59 +05:30
data_import fix: downcase email before finding (#8921) 2024-02-21 18:51:00 +05:30
email chore: Migrate mailers from the worker to jobs (#12331) 2025-10-21 16:36:37 -07:00
email_templates chore: Fix emails being sent with the wrong translations (#2236) 2021-06-08 22:45:01 +05:30
facebook feat: hide CSAT survey URLs from agents in dashboard (#11622) 2025-06-11 23:39:47 +05:30
geocoder fix: ip-lookup database lazy loading for all environments (#8052) 2024-10-22 23:18:30 -07:00
google feat: add Google Email fetch and OAuth token refresh service (#9603) 2024-06-11 14:22:03 +05:30
imap feat: add Google Email fetch and OAuth token refresh service (#9603) 2024-06-11 14:22:03 +05:30
instagram fix: Handle Instagram API error codes properly in message processing (#13002) 2025-12-04 18:53:50 +05:30
internal feat: add job to remove stale contacts and contact_inboxes (#11186) 2025-03-28 12:18:39 +05:30
labels fix: Update associations when a label is updated (#3046) 2021-09-21 10:16:32 +05:30
line fix: Ensure messages go to correct conversation when receive multi user in 1 LINE webhook (#12322) 2025-09-22 17:05:25 +05:30
linear feat: Add activity messages for linear actions (#11654) 2025-06-13 11:57:11 +05:30
liquid feat: Add liquid processing for SMS campaigns (#10981) 2025-06-11 13:16:44 -04:00
llm_formatter feat: Differentiate bot and user in the summary (#12801) 2025-11-05 11:42:21 -08:00
macros feat: Add webhook event support for macros (#11235) 2025-04-02 20:26:55 -07:00
mailbox refactor: strategy pattern for mailbox conversation finding (#12766) 2025-11-10 20:47:18 +05:30
message_templates fix: Disable automations on auto-reply emails (#12101) 2025-08-05 13:17:06 +05:30
messages chore(sidekiq): log ActiveJob class and job_id on dequeue (#12704) 2025-10-22 20:20:37 -07:00
mfa feat: MFA (#12290) 2025-09-18 20:19:24 +05:30
microsoft feat: add Google Email fetch and OAuth token refresh service (#9603) 2024-06-11 14:22:03 +05:30
notification chore: Handle WebPush rate limiting in push notification service (#12184) 2025-08-13 13:32:22 +05:30
sms fix: Error shouldn't halt the campaign for entire audience (#11980) 2025-08-11 12:03:48 +05:30
telegram feat: Enable lock to single thread settings for Telegram (#12367) 2025-09-24 11:35:14 +05:30
twilio fix: Extend phone number normalization to Twilio WhatsApp (#12655) 2025-10-28 18:16:29 +05:30
twitter feat: hide CSAT survey URLs from agents in dashboard (#11622) 2025-06-11 23:39:47 +05:30
whatsapp fix: Prevent WhatsApp campaign duplicate messages by updating status immediately (#12955) 2025-11-26 15:25:49 +05:30
widget feat: MFA (#12290) 2025-09-18 20:19:24 +05:30
account_deletion_service.rb feat: automate account deletion (#11406) 2025-05-23 12:58:13 +05:30
action_service.rb chore: Add open conversation option (#11828) 2025-07-02 10:01:50 +05:30
base_refresh_oauth_token_service.rb feat: add Google Email fetch and OAuth token refresh service (#9603) 2024-06-11 14:22:03 +05:30
base_token_service.rb feat: MFA (#12290) 2025-09-18 20:19:24 +05:30
csat_survey_service.rb fix: Send CSAT survey only when agent can reply in conversation (#11637) 2025-06-11 22:45:32 +05:30
filter_service.rb chore: Ability to filter conversations with priority (#10967) 2025-03-03 16:38:22 +05:30
ip_lookup_service.rb feat(poc): Disable widget based on country (#6658) 2023-03-14 09:09:57 -07:00
search_service.rb feat(ee): Setup advanced, performant message search (#12193) 2025-08-28 10:10:28 +05:30