fix(whatsapp): surface Meta's real error when an outbound call fails (#15178)

When an outbound WhatsApp call could not be placed, agents sometimes saw
a completely empty error (`{"error":""}`) with no indication of what
went wrong. This makes an outbound call that is blocked at Meta (for
example, a WhatsApp Business Account with a billing/eligibility problem)
look like a generic, unexplained failure. Agents now see the actual
reason Meta returned.

## Closes

No linked issue — found via a customer support investigation (outbound
calling returning `422 {"error":""}`).

## How to reproduce

1. On an account with WhatsApp calling enabled, place an outbound call
to a contact whose WhatsApp Business Account is not eligible for calling
(Meta returns error code `131044`, "Business eligibility payment issue
for calling").
2. Before: the call fails with `422 {"error":""}` — an empty message.
3. After: the call fails with Meta's actual message (e.g. "Business
eligibility payment issue for calling"), so the agent/admin knows it is
a Meta-side eligibility issue to resolve, not a Chatwoot bug.

## What changed

Meta's error responses can contain an **empty** `error_user_msg` (`""`)
while the real reason lives in `error.message` / `error_user_title` —
notably error `131044`. The previous code used `parsed.dig('error',
'error_user_msg') || 'Failed to initiate call'`, but an empty string is
truthy in Ruby, so the blank message was surfaced instead of the
fallback.

- Added a small `meta_error_message(parsed, default)` helper that
prefers the first **non-blank** field: `error_user_msg` → `message` →
`error_user_title` → default.
- Used it in both `process_initiate_call_response` (outbound call
initiate) and `update_calling_status`, which had the same pattern.

The `[WHATSAPP CALL] initiate_call failed: status=… body=…` server log
(with the full Meta body) is unchanged and remains the source of truth
for debugging.

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Tanmay Deep Sharma
2026-07-27 14:36:21 +05:30
committed by GitHub
parent 1fa9127a72
commit 5e82e971fa

View File

@@ -51,9 +51,9 @@ module Enterprise::Whatsapp::Providers::WhatsappCloudService
return true if response.success?
parsed = response.parsed_response.is_a?(Hash) ? response.parsed_response : {}
message = parsed.dig('error', 'error_user_msg') || parsed.dig('error', 'message') || 'Failed to update calling status'
error = parsed['error'].is_a?(Hash) ? parsed['error'] : {}
Rails.logger.error "[WHATSAPP CALL] update_calling_status failed: status=#{response.code} body=#{response.body}"
raise message
raise meta_error_message(error, 'Failed to update calling status')
end
private
@@ -102,11 +102,18 @@ module Enterprise::Whatsapp::Providers::WhatsappCloudService
Rails.logger.error "[WHATSAPP CALL] initiate_call failed: status=#{response.code} body=#{response.body}"
parsed = response.parsed_response.is_a?(Hash) ? response.parsed_response : {}
error_code = parsed.dig('error', 'code')
error_msg = parsed.dig('error', 'error_user_msg') || 'Failed to initiate call'
error = parsed['error'].is_a?(Hash) ? parsed['error'] : {}
error_code = error['code']
error_msg = meta_error_message(error, 'Failed to initiate call')
raise Voice::CallErrors::NoCallPermission, error_msg if error_code == Voice::CallErrors::NO_CALL_PERMISSION_CODE
raise Voice::CallErrors::CallFailed, error_msg
end
# Meta often returns a blank error_user_msg (e.g. code 131044 business-eligibility);
# an empty string is truthy, so `||` would surface it. Prefer the first non-blank field.
def meta_error_message(error, default)
error['error_user_msg'].presence || error['message'].presence || error['error_user_title'].presence || default
end
end