louislam/uptime-kuma · error · Error

Ooredoo rejected the message: ${reason}

Error message

Ooredoo rejected the message: ${reason}

What it means

The Ooredoo SMS gateway returns HTTP 200 even on logical failure, so the provider checks resp.data.response_code and treats non-zero as failure, throwing 'Ooredoo rejected the message: <reason>'. reason is resp.data.response_message when present, otherwise 'response_code=<code or unknown>'. This is the gateway-level acceptance check, distinct from a transport error.

Source

Thrown at server/notification-providers/ooredoo.js:59

                const batch = recipients.slice(i, i + MAX_RECIPIENTS_PER_REQUEST);
                const data = new URLSearchParams({
                    username: notification.ooredooUsername,
                    // The gateway expects the access key to be Base64 encoded.
                    access_key: Buffer.from(notification.ooredooAccessKey).toString("base64"),
                    message: msg,
                    batch: batch.join(" "),
                });

                const resp = await axios.post(url, data.toString(), config);

                // The gateway returns HTTP 200 even on failure; the real outcome
                // is carried in "response_code" (0 means the batch was accepted).
                if (!resp.data || Number(resp.data.response_code) !== 0) {
                    const reason =
                        resp.data && resp.data.response_message
                            ? resp.data.response_message
                            : "response_code=" + (resp.data ? resp.data.response_code : "unknown");
                    throw new Error("Ooredoo rejected the message: " + reason);
                }
            }

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

    /**
     * Normalize a Maldivian phone number to the "960XXXXXXX" format expected
     * by the Ooredoo gateway. Numbers already in that form are returned as is.
     * @param {string} phoneNumber The phone number to normalize
     * @returns {string} The normalized phone number, or "" if it is empty
     */
    normalizePhoneNumber(phoneNumber) {
        const number = phoneNumber.replace(/[\s+]/g, "");

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Read response_message in the surfaced error to get the gateway's stated reason and act on it (top up credit, fix sender id, etc.).
  2. Confirm ooredooBearerToken is the current valid token and the account is active in the Ooredoo portal.
  3. Validate recipient numbers pass normalizePhoneNumber before sending (see error 171).
  4. If response_code is missing entirely, treat it as a gateway/envelope change and inspect resp.data.
Defensive patterns

Strategy: try-catch

Validate before calling

if (!notification.ooredooBearerToken) {
    throw new Error("ooredooBearerToken is required");
}

Type guard

/** @param {unknown} data */
function isOoredooAccepted(data) {
    return data && typeof data === "object" && Number(data.response_code) === 0;
}

Try / catch

const resp = await axios.post(url, data.toString(), config);
if (!isOoredooAccepted(resp.data)) {
    const reason = resp.data?.response_message || `response_code=${resp.data?.response_code ?? "unknown"}`;
    throw new Error(`Ooredoo rejected the message: ${reason}`);
}

Prevention

When it happens

Trigger: response_code !== 0: invalid/insufficient credit, malformed recipient numbers rejected by the gateway, wrong sender id, expired/invalid ooredooBearerToken accepted at transport but rejected at logic, or rate/quota limits.

Common situations: Ooredoo account out of credits; sender id not approved; recipient numbers blacklisted/off-network; token valid for auth but account suspended.

Related errors


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