louislam/uptime-kuma · warning · TranslatableError

domain_expiry_unsupported_is_icann

Error message

domain_expiry_unsupported_is_icann

What it means

After confirming a non-empty target string, checkSupport runs tldts.parse on it and checks tld.isIcann. If the suffix is not on the ICANN list (private TLDs like .local, .test, .internal, .home, or suffixes from a private network), this TranslatableError is thrown with domain/publicSuffix in meta for the frontend to interpolate.

Source

Thrown at server/model/domain_expiry.js:225

     * @param {Monitor} monitor Monitor object
     * @throws {TranslatableError} Throws an error if the monitor type is unsupported or missing target.
     * @returns {Promise<{ domain: string, tld: string }>} Domain expiry support info
     */
    static async checkSupport(monitor) {
        if (!(monitor.type in TYPES_WITH_DOMAIN_EXPIRY_SUPPORT_VIA_FIELD)) {
            throw new TranslatableError("domain_expiry_unsupported_monitor_type");
        }
        const targetField = TYPES_WITH_DOMAIN_EXPIRY_SUPPORT_VIA_FIELD[monitor.type];
        const target = monitor[targetField];
        if (typeof target !== "string" || target.length === 0) {
            throw new TranslatableError("domain_expiry_unsupported_missing_target");
        }

        const tld = parseTld(target);

        // It must be checked first, filter out non-ICANN domains.
        if (!tld.isIcann) {
            throw new TranslatableError("domain_expiry_unsupported_is_icann", {
                // If domain is null, use hostname as fallback for better error message.
                domain: tld.domain ?? tld.hostname ?? "EMPTY DOMAIN",
                publicSuffix: tld.publicSuffix,
            });
        }

        const publicSuffix = tld.publicSuffix;
        const rootTld = publicSuffix.split(".").pop();
        const rdap = await getRdapServer(publicSuffix);
        if (!rdap) {
            throw new TranslatableError("domain_expiry_unsupported_unsupported_tld_no_rdap_endpoint", {
                publicSuffix,
            });
        }

        return {
            domain: tld.domain,
            tld: rootTld,

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Use a real ICANN-registered domain for the monitor if you want expiry tracking (e.g. point the monitor at the public name even if it resolves internally).
  2. If you can only monitor an internal name, accept that domain-expiry is not applicable — disable the domain-expiry option for that monitor.
  3. Confirm the URL is parsed as you expect with `require('tldts').parse('http://myapp.local')` and inspect .isIcann and .publicSuffix.
  4. Do not try to fake an ICANN suffix; the underlying data simply has no expiry date.

Example fix

// before
// monitor.url = "http://grafana.local"
await DomainExpiry.checkSupport(monitor); // throws domain_expiry_unsupported_is_icann

// after — monitor a real registered domain instead
// monitor.url = "http://grafana.example.com"
Defensive patterns

Strategy: validation

Validate before calling

const { parse: parseTld } = require("tldts");
function isIcannDomain(target) {
    const tld = parseTld(target);
    return tld.isIcann === true;
}

Type guard

function hasIcannSuffix(target) {
    return parseTld(target).isIcann === true;
}

Try / catch

try {
    await DomainExpiry.checkSupport(monitor);
} catch (e) {
    if (e.msgi18n && e.message === "domain_expiry_unsupported_is_icann") {
        // domain is internal/private — disable the expiry option
    }
}

Prevention

When it happens

Trigger: An http monitor pointed at an internal name like http://myapp.local, http://grafana.internal, http://service.test, or an IP address where tldts cannot find an ICANN suffix. Any hostname whose public suffix is not in the Public Suffix List as ICANN-managed.

Common situations: Internal/home-lab monitoring of LAN services; monitoring by raw IP; private TLDs used for service discovery; test environments using .test or .example.

Related errors


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