louislam/uptime-kuma · error · Error

Invalid domain

Error message

Invalid domain

What it means

Thrown by StatusPage.updateDomainNameList when an element of the domainNameList array is not a string. Each entry is stored verbatim in status_page_cname.domain, so non-string values would break CNAME matching and DNS routing.

Source

Thrown at server/model/status_page.js:396

    /**
     * Update list of domain names
     * @param {string[]} domainNameList List of status page domains
     * @returns {Promise<void>}
     */
    async updateDomainNameList(domainNameList) {
        if (!Array.isArray(domainNameList)) {
            throw new Error("Invalid array");
        }

        let trx = await R.begin();

        await trx.exec("DELETE FROM status_page_cname WHERE status_page_id = ?", [this.id]);

        try {
            for (let domain of domainNameList) {
                if (typeof domain !== "string") {
                    throw new Error("Invalid domain");
                }

                if (domain.trim() === "") {
                    continue;
                }

                // If the domain name is used in another status page, delete it
                await trx.exec("DELETE FROM status_page_cname WHERE domain = ?", [domain]);

                let mapping = trx.dispense("status_page_cname");
                mapping.status_page_id = this.id;
                mapping.domain = domain;
                await trx.store(mapping);
            }
            await trx.commit();
        } catch (error) {
            await trx.rollback();
            throw error;

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Ensure every element is a string; coerce with String(x) or filter non-strings out beforehand.
  2. If your source data uses objects, map them: list.map(o => o.domain).
  3. Validate with list.every(d => typeof d === "string") before calling.

Example fix

// before
await statusPage.updateDomainNameList([ { domain: "status.example.com" } ]);
// after
await statusPage.updateDomainNameList([ "status.example.com" ]);
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizeDomains(list) {
  return list.map(d => typeof d === "object" && d ? d.domain : d).filter(d => typeof d === "string");
}

Type guard

function isStringArray(list) {
  return Array.isArray(list) && list.every(d => typeof d === "string");
}

Try / catch

try {
  await statusPage.updateDomainNameList(list);
} catch (e) {
  if (/Invalid domain/.test(e.message)) return badRequest("every domain must be a string");
  throw e;
}

Prevention

When it happens

Trigger: Call updateDomainNameList with [123, "x"], [null], [{domain:"x"}], or [true]. The check fires inside the per-domain loop after the array guard but before the empty-trim short-circuit.

Common situations: Mixed-type arrays from loosely-typed API clients. Object-wrapped domains from an import format that uses {domain: "..."}. Numeric IDs accidentally placed in the domain field.

Related errors


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