{"record":{"id":"57dc0cb609fd61c1","repo":"louislam/uptime-kuma","slug":"unexpected-output-line","errorCode":null,"errorMessage":"Unexpected output: \"${line}\"","messagePattern":"Unexpected output: \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"server/monitor-types/tailscale-ping.js","lineNumber":69,"sourceCode":"    parseTailscaleOutput(tailscaleOutput, heartbeat) {\n        let lines = tailscaleOutput.split(\"\\n\");\n\n        for (let line of lines) {\n            if (line.includes(\"pong from\")) {\n                heartbeat.status = UP;\n                let time = line.split(\" in \")[1].split(\" \")[0];\n                heartbeat.ping = parseInt(time);\n                heartbeat.msg = \"OK\";\n                break;\n            } else if (line.includes(\"timed out\")) {\n                throw new Error(`Ping timed out: \"${line}\"`);\n                // Immediately throws upon \"timed out\" message, the server is expected to re-call the check function\n            } else if (line.includes(\"no matching peer\")) {\n                throw new Error(`Nonexistant or inaccessible due to ACLs: \"${line}\"`);\n            } else if (line.includes(\"is local Tailscale IP\")) {\n                throw new Error(`Tailscale only works if used on other machines: \"${line}\"`);\n            } else if (line !== \"\") {\n                throw new Error(`Unexpected output: \"${line}\"`);\n            }\n        }\n    }\n}\n\nmodule.exports = {\n    TailscalePing,\n};\n","sourceCodeStart":51,"sourceCodeEnd":78,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/tailscale-ping.js#L51-L78","documentation":"Thrown by parseTailscaleOutput() for any non-empty line that does not match the known 'pong from', 'timed out', 'no matching peer', or 'is local Tailscale IP' substrings. It is the fallback branch signalling that the installed tailscale CLI produced output the parser was not written to understand.","triggerScenarios":"Produced when a newer (or older) tailscale version changes the ping output phrasing, adds a new status line, prints a warning banner, or emits locale-specific text that does not contain any recognised token.","commonSituations":"Tailscale CLI upgraded to a version that reworded status lines; a preface/warning (e.g. 'needs login', update notice) printed before the pong; non-English locale affecting output; experimental tailscale build with extra telemetry lines.","solutions":["Run 'tailscale ping --c 1 <hostname>' manually and compare the actual line text to the substrings the parser checks.","If the wording changed, update parseTailscaleOutput() to recognise the new token (and keep the unexpected-output fallback).","Suppress preface banners or ensure the environment locale is English (LC_ALL=C) for stable parsing.","Pin the tailscale CLI version in deployments until the parser is updated."],"exampleFix":"// before\n} else if (line !== \"\") {\n    throw new Error(`Unexpected output: \"${line}\"`);\n}\n\n// after — extend recognised tokens before falling back\n} else if (line.includes(\"via DERP\")) {\n    // relayed pong, still a success-ish signal; handle accordingly\n} else if (line !== \"\") {\n    throw new Error(`Unexpected output: \"${line}\"`);\n}","handlingStrategy":"validation","validationCode":"const KNOWN_TOKENS = [\"pong from\", \"timed out\", \"no matching peer\", \"is local Tailscale IP\"];\nfunction isKnownLine(line) { return line === \"\" || KNOWN_TOKENS.some(t => line.includes(t)); }","typeGuard":"function isKnownLine(line) { return line === \"\" || KNOWN_TOKENS.some(t => line.includes(t)); }","tryCatchPattern":"if (!isKnownLine(line)) { log.warn(\"tailscale\", `Unrecognised line: ${line}`); heartbeat.status = DOWN; heartbeat.msg = `Unexpected output: \"${line}\"`; }","preventionTips":["Pin the tailscale CLI version until the parser recognises its output.","Force LC_ALL=C so output phrasing stays stable.","Extend KNOWN_TOKENS when a new tailscale version rewords status lines."],"tags":["tailscale","parsing","versioning","vpn"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}