{"record":{"id":"a916e442aff04d38","repo":"louislam/uptime-kuma","slug":"smseagle-api-returned-error-json-stringify-resp","errorCode":null,"errorMessage":"SMSEagle API returned error: ${JSON.stringify(resp.data)}","messagePattern":"SMSEagle API returned error: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/notification-providers/smseagle.js","lineNumber":129,"sourceCode":"                        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":111,"sourceCodeEnd":145,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/notification-providers/smseagle.js#L111-L145","documentation":"Thrown by the SMSEagle apiv2 path when the response is non-200 or zero recipients queued, but resp.data is a non-empty array. Each array element is a per-recipient status object; if none has status 'queued' (e.g. all 'rejected', 'failed', 'invalid'), the entire JSON payload is stringified into the error so the operator can see which recipients failed and why.","triggerScenarios":"All recipients rejected by the device (invalid number, blocked, duplicate, quota exhausted), a 4xx from the gateway with a structured error array, or recipients marked 'sent'/'delivered' but never 'queued' (status filter mismatch after a firmware change).","commonSituations":"Recipient list contains stale numbers, device SIM out of credit, recipients on a blocklist, or firmware upgrade renaming 'queued' to 'accepted' so the filter returns zero.","solutions":["Read the JSON in the error: each object's status/message field names the failing recipient and reason.","Remove or correct the specific recipients flagged as rejected/failed in the payload.","Top up SMS credits on the device SIM and confirm the modem is online.","If the device firmware renamed the status value, update the queuedCount filter (smseagle.js:122) to also accept the new value (e.g. 'accepted')."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"/** True when every recipient object carries a recognizable status. */\nfunction isSmseagleV2OutcomeArray(data) {\n    return Array.isArray(data) && data.every((x) => x && [\"queued\",\"sent\",\"rejected\",\"failed\",\"invalid\"].includes(x.status));\n}","tryCatchPattern":"try {\n    const resp = await axios.post(url, postData, config);\n    const queued = Array.isArray(resp.data) ? resp.data.filter((x) => x.status === \"queued\").length : 0;\n    if (resp.status !== 200 || queued === 0) {\n        throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);\n    }\n} catch (err) {\n    this.throwGeneralAxiosError(err);\n}","preventionTips":["Keep recipient lists current; prune retired numbers periodically.","Monitor device credit/modem status from the SMSEagle UI.","Track the firmware 'queued' status name across upgrades."],"tags":["smseagle","notification-provider","api-response","diagnostics"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}