louislam/uptime-kuma · error · Error

Failed to create measurement: ${this.formatApiError(res.data

Error message

Failed to create measurement: ${this.formatApiError(res.data.error)}

What it means

Thrown by the Globalping monitor when createMeasurement returns a non-ok, non-429, non-500 response. formatApiError renders the Globalping error object as "<type> <message>.\n<param>: <value>...". A single 500 is auto-retried before this throw; anything else (400 validation, 401/403 auth, 404, 5xx that persisted) lands here.

Source

Thrown at server/monitor-types/globalping.js:102

        if (monitor.ipFamily === "ipv4") {
            opts.measurementOptions.ipVersion = IpVersion[4];
        } else if (monitor.ipFamily === "ipv6") {
            opts.measurementOptions.ipVersion = IpVersion[6];
        }

        log.debug("monitor", `Globalping create measurement: ${JSON.stringify(opts)}`);
        let res = await client.createMeasurement(opts);

        // Retry if the server returns a 500 error
        if (!res.ok && Globalping.isHttpStatus(500, res)) {
            res = await client.createMeasurement(opts);
        }

        if (!res.ok) {
            if (Globalping.isHttpStatus(429, res)) {
                throw new Error(`Failed to create measurement: ${this.formatTooManyRequestsError(hasAPIToken)}`);
            }
            throw new Error(`Failed to create measurement: ${this.formatApiError(res.data.error)}`);
        }

        log.debug("monitor", `Globalping fetch measurement: ${res.data.id}`);
        let measurement = await client.awaitMeasurement(res.data.id);

        if (!measurement.ok) {
            throw new Error(
                `Failed to fetch measurement (${res.data.id}): ${this.formatApiError(measurement.data.error)}`
            );
        }

        const probe = measurement.data.results[0].probe;
        const result = measurement.data.results[0].result;

        if (result.status === "failed") {
            throw new Error(this.formatResponse(probe, `Failed: ${result.rawOutput}`));
        }

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Read the embedded <type> and <message>: validation errors name the offending field.
  2. For 401/403, refresh or re-enter the Globalping API token in settings.
  3. For location errors, use a known magic location (e.g. a region or 'magic+ww' style) from Globalping docs.
  4. For 5xx that is not 500, treat as transient and retry after a short delay; check status.globalping.io.
Defensive patterns

Strategy: try-catch

Validate before calling

function validateMeasurementInput(monitor) {
  if (monitor.protocol === "TCP" && !monitor.port) throw new Error("TCP measurements require a port");
  if (!monitor.hostname) throw new Error("hostname is required");
  return true;
}

Type guard

function isPlausibleGlobalpingTarget(monitor) {
  return Boolean(monitor?.hostname) && (monitor.protocol !== "TCP" || Number.isFinite(Number(monitor?.port)));
}

Try / catch

try {
  await gp.monitor(client, monitor, heartbeat, hasToken);
} catch (e) {
  if (/Failed to create measurement/.test(e.message) && !/run out of credits/.test(e.message)) {
    heartbeat.status = DOWN; heartbeat.msg = e.message; return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Submit a measurement with an invalid target/protocol/location/port combo (400), an expired or invalid API token (401/403), an unknown location magic string, or hit a Globalping outage returning 502/503 that the 500-retry did not cover.

Common situations: Wrong protocol for the measurement type (e.g. TCP without a port, set via monitor.protocol/port), unsupported location string, stale API token, Globalping maintenance window, breaking API change after a version bump.

Related errors


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