louislam/uptime-kuma · error · Error

Nonexistant or inaccessible due to ACLs

Error message

Nonexistant or inaccessible due to ACLs: "${line}"

What it means

Thrown by parseTailscaleOutput() when an output line contains 'no matching peer'. Tailscale emits this when the target name/IP does not correspond to any node in the current tailnet, or when ACL rules prevent the source from reaching that peer.

Solutions

  1. Run 'tailscale status' and confirm the target appears in the peer list with the name/IP used in the monitor.
  2. Verify ACL policy grants the source node access to the target.
  3. Correct the hostname/IP in the monitor to match a listed peer.
  4. If the peer was removed, re-invite/rejoin it to the tailnet.
Defensive patterns

Strategy: validation

Validate before calling

function isNoMatchingPeer(line) { return typeof line === "string" && line.includes("no matching peer"); }

Type guard

function isKnownPeer(peerName, status) { return status.some(p => p.name === peerName || p.ip === peerName); }

Try / catch

if (isNoMatchingPeer(line)) { heartbeat.status = DOWN; heartbeat.msg = `Inaccessible due to ACLs: "${line}"`; return; }

Prevention

When it happens

Trigger: Produced when 'tailscale ping <hostname>' cannot map the target to a known peer — either the name is wrong, the peer left the tailnet, or the tailnet ACLs deny access from this node to the target.

Common situations: Typo in the target hostname/IP; target was removed from the tailnet; user's role lacks access to that node per ACL policy; tailnet key rotation removed the peer; pinging a name from a different tailnet than intended.

Related errors


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

Appendix: source

Thrown at server/monitor-types/tailscale-ping.js:65

     * @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)