louislam/uptime-kuma · error · Error

SMSEagle API returned error: ${JSON.stringify(resp.data)}

Error message

SMSEagle API returned error: ${JSON.stringify(resp.data)}

What it means

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.

Source

Thrown at server/notification-providers/smseagle.js:129

                        endpoint = "/calls/ring";
                    } else if (notification.smseagleMsgType === "smseagle-tts") {
                        endpoint = "/calls/tts";
                    } else if (notification.smseagleMsgType === "smseagle-tts-advanced") {
                        endpoint = "/calls/tts_advanced";
                        postData["voice_id"] = notification.smseagleTtsModel ?? 1;
                    }
                }

                let resp = await axios.post(notification.smseagleUrl + "/api/v2" + endpoint, postData, config);

                const queuedCount = resp.data.filter((x) => x.status === "queued").length;
                const unqueuedCount = resp.data.length - queuedCount;

                if (resp.status !== 200 || queuedCount === 0) {
                    if (!resp.data.length) {
                        throw new Error("SMSEagle API returned an empty response");
                    }
                    throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);
                }

                if (unqueuedCount) {
                    return `Sent ${queuedCount}/${resp.data.length} Messages Successfully.`;
                }

                return okMsg;
            }
        } catch (error) {
            this.throwGeneralAxiosError(error);
        }
    }
}

module.exports = SMSEagle;

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Read the JSON in the error: each object's status/message field names the failing recipient and reason.
  2. Remove or correct the specific recipients flagged as rejected/failed in the payload.
  3. Top up SMS credits on the device SIM and confirm the modem is online.
  4. If the device firmware renamed the status value, update the queuedCount filter (smseagle.js:122) to also accept the new value (e.g. 'accepted').
Defensive patterns

Strategy: try-catch

Type guard

/** True when every recipient object carries a recognizable status. */
function isSmseagleV2OutcomeArray(data) {
    return Array.isArray(data) && data.every((x) => x && ["queued","sent","rejected","failed","invalid"].includes(x.status));
}

Try / catch

try {
    const resp = await axios.post(url, postData, config);
    const queued = Array.isArray(resp.data) ? resp.data.filter((x) => x.status === "queued").length : 0;
    if (resp.status !== 200 || queued === 0) {
        throw new Error(`SMSEagle API returned error: ${JSON.stringify(resp.data)}`);
    }
} catch (err) {
    this.throwGeneralAxiosError(err);
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/a916e442aff04d38. Report an issue: GitHub.