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:
committed by
GitHub
parent
1fa9127a72
commit
5e82e971fa
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user