louislam/uptime-kuma · error · Error

${res.status()}

Error message

${res.status()}

What it means

After navigation and screenshot capture, the monitor reads res.status() (Playwright HTTP status of the main response). Statuses in [200,400) are UP; anything else (>=400 or an error status) is thrown as res.status() + '' so the heartbeat is marked DOWN with the code. This converts a non-success HTTP response into a monitor failure.

Source

Thrown at server/monitor-types/real-browser-monitor-type.js:292

            await page.waitForTimeout(monitor.screenshot_delay);
        }

        let filename = jwt.sign(monitor.id, server.jwtSecret) + ".png";

        await page.screenshot({
            path: path.join(Database.screenshotDir, filename),
        });

        await context.close();

        if (res.status() >= 200 && res.status() < 400) {
            heartbeat.status = UP;
            heartbeat.msg = res.status();

            const timing = res.request().timing();
            heartbeat.ping = timing.responseEnd;
        } else {
            throw new Error(res.status() + "");
        }
    }
}

module.exports = {
    RealBrowserMonitorType,
    testChrome,
    resetChrome,
    testRemoteBrowser,
};

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Open the URL in a browser and confirm the HTTP status (DevTools Network or curl -i).
  2. Fix the upstream service returning the error code.
  3. If the error page is intentional, point the monitor at the real resource URL.
  4. For 502/504 from a reverse proxy, check the backend service health.

Example fix

# before
GET / -> 502 Bad Gateway
# after
# restart the backend behind the reverse proxy, then re-test
Defensive patterns

Strategy: validation

Validate before calling

const http = require('http');
function preflightHttp(url) {
  return new Promise((resolve, reject) => {
    http.get(url, res => {
      if (res.statusCode >= 400) reject(new Error(`Preflight: HTTP ${res.statusCode}`));
      else resolve(res.statusCode);
    }).on('error', reject);
  });
}

Type guard

function isHttpErrorStatus(code) { return typeof code === 'number' && code >= 400; }

Try / catch

try {
  await realBrowserMonitor.check(monitor, heartbeat, server);
} catch (e) {
  if (/^\d{3}$/.test(e.message)) {
    heartbeat.status = DOWN;
    heartbeat.msg = `HTTP ${e.message}`;
  }
}

Prevention

When it happens

Trigger: The page responded with an HTTP error: 404, 500, 502, 503, etc. The response object exists (navigation completed) but the status code is >= 400, so the else branch at real-browser-monitor-type.js:292 throws.

Common situations: Target page returning 404/500, upstream gateway 502/504, redirect to an error page, or maintenance pages served with a non-2xx code.

Related errors


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