{"record":{"id":"ab6193da3e748d0a","repo":"louislam/uptime-kuma","slug":"smseagle-api-returned-an-empty-response","errorCode":null,"errorMessage":"SMSEagle API returned an empty response","messagePattern":"SMSEagle API returned an empty response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/notification-providers/smseagle.js","lineNumber":127,"sourceCode":"\n                    if (notification.smseagleMsgType === \"smseagle-ring\") {\n                        endpoint = \"/calls/ring\";\n                    } else if (notification.smseagleMsgType === \"smseagle-tts\") {\n                        endpoint = \"/calls/tts\";\n                    } else if (notification.smseagleMsgType === \"smseagle-tts-advanced\") {\n                        endpoint = \"/calls/tts_advanced\";\n                        postData[\"voice_id\"] = notification.smseagleTtsModel ?? 1;\n                    }\n                }\n\n                let resp = await axios.post(notification.smseagleUrl + \"/api/v2\" + endpoint, postData, config);\n\n                const queuedCount = resp.data.filter((x) => x.status === \"queued\").length;\n                const unqueuedCount = resp.data.length - queuedCount;\n\n                if (resp.status !== 200 || queuedCount === 0) {\n                    if (!resp.data.length) {\n                        throw new Error(\"SMSEagle API returned an empty response\");\n                    }\n                    throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);\n                }\n\n                if (unqueuedCount) {\n                    return `Sent ${queuedCount}/${resp.data.length} Messages Successfully.`;\n                }\n\n                return okMsg;\n            }\n        } catch (error) {\n            this.throwGeneralAxiosError(error);\n        }\n    }\n}\n\nmodule.exports = SMSEagle;\n","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/notification-providers/smseagle.js#L109-L145","documentation":"Thrown by the SMSEagle apiv2 path when the HTTP response is non-200 OR no recipients landed in 'queued' status, AND resp.data is an empty array (length 0). The v2 /api/v2 endpoints return an array of per-recipient status objects; an empty array means the gateway accepted the request but produced zero deliverable status entries, so there is nothing to report.","triggerScenarios":"POST to {smseagleUrl}/api/v2/messages/sms or /api/v2/calls/* with an empty to/contacts/groups payload, or the device returning 200 with [] because all recipients were filtered out server-side. Also reachable when the device returns a non-2xx status with no body.","commonSituations":"smseagleRecipientTo/Contact/Group fields left blank while apiv2 is selected, comma-separated IDs that all fail to parse via .map(Number) producing NaN entries the device rejects, or a firmware bug returning [] on internal failure.","solutions":["In the notification config, ensure at least one of smseagleRecipientTo, smseagleRecipientContact, or smseagleRecipientGroup is populated with valid values.","Confirm the device firmware supports apiv2 and the {smseagleUrl}/api/v2 base path resolves (visit {smseagleUrl}/api/v2/ping).","Check that numeric recipient IDs (contacts/groups) are valid integers — non-numeric strings become NaN after .map(Number) and are silently dropped.","Reproduce the POST with curl using the access-token header to inspect the raw array the device returns."],"exampleFix":"// before\nif (resp.status !== 200 || queuedCount === 0) {\n    if (!resp.data.length) {\n        throw new Error(\"SMSEagle API returned an empty response\");\n    }\n    throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);\n}\n// after (surface which recipient source was missing for faster diagnosis)\nconst hasRecipient = postData.to?.length || postData.contacts?.length || postData.groups?.length;\nif (resp.status !== 200 || queuedCount === 0) {\n    if (!resp.data.length) {\n        throw new Error(`SMSEagle API returned an empty response (recipients sent: ${!!hasRecipient})`);\n    }\n    throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);\n}","handlingStrategy":"validation","validationCode":"// Ensure at least one recipient source is set before calling the v2 endpoint\nconst hasRecipient =\n    (notification.smseagleRecipientTo && notification.smseagleRecipientTo.trim()) ||\n    (notification.smseagleRecipientContact && notification.smseagleRecipientContact.trim()) ||\n    (notification.smseagleRecipientGroup && notification.smseagleRecipientGroup.trim());\nif (!hasRecipient) {\n    throw new Error(\"At least one SMSEagle recipient (to/contact/group) is required for apiv2\");\n}","typeGuard":"/** True when the v2 response is a non-empty array of status objects. */\nfunction isSmseagleV2StatusArray(data) {\n    return Array.isArray(data) && data.length > 0 && data.every((x) => x && typeof x.status === \"string\");\n}","tryCatchPattern":"try {\n    const resp = await axios.post(url, postData, config);\n    if (!Array.isArray(resp.data)) {\n        throw new Error(`SMSEagle v2 returned non-array body: ${JSON.stringify(resp.data)}`);\n    }\n    if (resp.status !== 200 || resp.data.filter((x) => x.status === \"queued\").length === 0) {\n        if (resp.data.length === 0) throw new Error(\"SMSEagle API returned an empty response\");\n        throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);\n    }\n} catch (err) {\n    this.throwGeneralAxiosError(err);\n}","preventionTips":["Always set at least one recipient field when apiv2 is selected.","Use integer IDs for contacts/groups so .map(Number) does not yield NaN.","Smoke-test apiv2 with one recipient before going wide."],"tags":["smseagle","notification-provider","api-response","config"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}