louislam/uptime-kuma · error · Error
No output from Tailscale ping
Error message
No output from Tailscale ping
What it means
Thrown by runTailscalePing() when the spawn resolved with neither a stderr error (code 0 or empty stderr) nor any stdout. The command produced no parseable output at all, so there is nothing to feed to parseTailscaleOutput().
Source
Thrown at server/monitor-types/tailscale-ping.js:40
* Runs the Tailscale ping command to the given URL.
* @param {string} hostname The hostname to ping.
* @param {number} interval Interval to send ping
* @returns {Promise<string>} A Promise that resolves to the output of the Tailscale ping command
* @throws Will throw an error if the command execution encounters any error.
*/
async runTailscalePing(hostname, interval) {
let timeout = interval * 1000 * 0.8;
let res = await childProcessAsync.spawn("tailscale", ["ping", "--c", "1", hostname], {
timeout: timeout,
encoding: "utf8",
});
if (res.stderr && res.stderr.toString() && res.code !== 0) {
throw new Error(`Error in output: ${res.stderr.toString()}`);
}
if (res.stdout && res.stdout.toString()) {
return res.stdout.toString();
} else {
throw new Error("No output from Tailscale ping");
}
}
/**
* 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);View on GitHub (pinned to 6b5ea01557)
Solutions
- Run the same 'tailscale ping --c 1 <hostname>' command manually and confirm it actually prints to stdout.
- Check the monitor interval — a very small interval yields a tiny timeout; raise it so the command has time to emit output.
- Restart tailscaled if it is in an odd state producing no output.
- Inspect whether a shell alias or container entrypoint is redirecting stdout.
Defensive patterns
Strategy: validation
Validate before calling
function hasStdout(res) { return !!res?.stdout && res.stdout.toString().trim().length > 0; } Type guard
function hasStdout(res) { return !!res?.stdout && res.stdout.toString().trim().length > 0; } Try / catch
if (!hasStdout(res)) { heartbeat.status = DOWN; heartbeat.msg = "No output from Tailscale ping"; return; } Prevention
- Set a monitor interval large enough to let tailscale ping emit output.
- Confirm the daemon is healthy and produces stdout when run manually.
- Avoid wrappers that redirect stdout.
When it happens
Trigger: Produced when 'tailscale ping' exits successfully (code 0) but writes nothing to stdout, or when stdout is empty/whitespace-only. Can happen with abnormal daemon states, SIGPIPE, or a successful exit before any line is flushed.
Common situations: Daemon in an inconsistent state returning immediately; very short timeout (interval * 0.8) cutting the process off before output flushes; tailscale version that writes everything to stderr with code 0; a wrapper/alias swallowing stdout in the deployment.
Related errors
- Error checking Tailscale ping: ${err}
- Error in output: ${res.stderr.toString()}
- Ping timed out: "${line}"
- Nonexistant or inaccessible due to ACLs: "${line}"
- Tailscale only works if used on other machines: "${line}"
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/38ebbae62f7e7970.
Report an issue: GitHub.