louislam/uptime-kuma · warning · Error
Ping timed out: "${line}"
Error message
Ping timed out: "${line}" What it means
Thrown by parseTailscaleOutput() when a line of the tailscale ping output contains 'timed out'. This is the expected signal that the target Tailscale node did not respond to the ping within the CLI's window; the monitor treats it as a DOWN condition and relies on the scheduler to retry on the next interval.
Source
Thrown at server/monitor-types/tailscale-ping.js:62
/**
* Parses the output of the Tailscale ping command to update the heartbeat.
* @param {string} tailscaleOutput The output of the Tailscale ping command.
* @param {object} heartbeat The heartbeat object to update.
* @returns {void}
* @throws Will throw an eror if the output contains any unexpected string.
*/
parseTailscaleOutput(tailscaleOutput, heartbeat) {
let lines = tailscaleOutput.split("\n");
for (let line of lines) {
if (line.includes("pong from")) {
heartbeat.status = UP;
let time = line.split(" in ")[1].split(" ")[0];
heartbeat.ping = parseInt(time);
heartbeat.msg = "OK";
break;
} else if (line.includes("timed out")) {
throw new Error(`Ping timed out: "${line}"`);
// Immediately throws upon "timed out" message, the server is expected to re-call the check function
} else if (line.includes("no matching peer")) {
throw new Error(`Nonexistant or inaccessible due to ACLs: "${line}"`);
} else if (line.includes("is local Tailscale IP")) {
throw new Error(`Tailscale only works if used on other machines: "${line}"`);
} else if (line !== "") {
throw new Error(`Unexpected output: "${line}"`);
}
}
}
}
module.exports = {
TailscalePing,
};
View on GitHub (pinned to 6b5ea01557)
Solutions
- Confirm the target machine is online and tailscaled is running on it ('tailscale status' on the source should show it).
- Check 'tailscale status' for the peer's relay/direct status and 'tailscale netcheck' for local network conditions.
- If persistent, review ACLs and firewall rules blocking UDP 41641 (or the configured port).
- Treat transient timeouts as recoverable; the scheduler will retry on the next interval automatically.
Defensive patterns
Strategy: try-catch
Validate before calling
function isTimeoutLine(line) { return typeof line === "string" && line.includes("timed out"); } Type guard
function isPongLine(line) { return typeof line === "string" && line.includes("pong from"); } Try / catch
if (isTimeoutLine(line)) { heartbeat.status = DOWN; heartbeat.msg = `Ping timed out: "${line}"`; return; } Prevention
- Confirm the target node is online with 'tailscale status'.
- Allow UDP for the WireGuard port through firewalls.
- Treat transient timeouts as retryable; let the scheduler re-run.
When it happens
Trigger: Produced when 'tailscale ping' reports a timeout line (e.g. 'pong from ... ' was not received and the output contains 'timed out'). The peer is reachable in the control plane but did not answer the DERP/direct ping in time.
Common situations: Target node offline or suspended; high latency or packet loss on the path; DERP relay congested and direct connection not established; target behind a restrictive firewall blocking WireGuard UDP; node in a tailnet that recently changed keysets.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Per-ping timeout must be between ${PING_PER_REQUEST_TIMEOUT_
- Timeout must be between ${PING_GLOBAL_TIMEOUT_MIN} and ${PIN
- Error checking Tailscale ping: ${err}
- Error in output: ${res.stderr.toString()}
- No output from Tailscale ping
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/3a92533dc0b2e9c9.
Report an issue: GitHub.