xpipe-io/xpipe · critical · BeaconClientException

Authentication failed

Error message

Authentication failed

What it means

The beacon handshake endpoint validates the auth value supplied by the client via checkAuth(). If the auth key/token does not match what the daemon expects, the entire handshake is rejected with a generic 'Authentication failed' message — the daemon deliberately does not reveal why. All subsequent beacon API calls require a successful handshake first.

Source

Thrown at app/src/main/java/io/xpipe/app/beacon/api/HandshakeExchange.java:40

    @Override
    public boolean requiresAuthentication() {
        return false;
    }

    @Override
    public String getPath() {
        return "/handshake";
    }

    @Override
    public boolean requiresCompletedStartup() {
        return false;
    }

    @Override
    public Object handle(HttpExchange exchange, Request request) throws BeaconClientException {
        if (!checkAuth(request.getAuth())) {
            throw new BeaconClientException("Authentication failed");
        }

        TrackEvent.withTrace("Handshake request received")
                .tag("client", request.getClient().toDisplayString())
                .handle();

        var session = new BeaconSession(request.getClient(), UUID.randomUUID().toString());
        AppBeaconServer.get().addSession(session);
        return Response.builder().sessionToken(session.getToken()).build();
    }

    @Override
    public boolean requiresEnabledApi() {
        return false;
    }

    private boolean checkAuth(io.xpipe.app.beacon.BeaconAuthMethod authMethod) {
        if (authMethod instanceof BeaconAuthMethod.Local local) {

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Re-read the current beacon auth key from the daemon's key file location and retry the handshake
  2. Confirm you are connecting to the intended daemon instance/port (not another local daemon)
  3. Restart the client so it performs a fresh handshake instead of reusing a cached key
  4. Check file permissions so the client process can read the key file

Example fix

// before
handshake(client, cachedAuthKey);
// after
String key = Files.readString(daemonKeyFile).trim();
if (!Objects.equals(key, cachedAuthKey)) {
    cachedAuthKey = key;
}
handshake(client, cachedAuthKey);
Defensive patterns

Strategy: try-catch

Validate before calling

String key = Files.readString(daemonKeyFile).trim();
if (key.isEmpty()) throw new IllegalStateException("Beacon auth key file is empty");

Try / catch

try {
    client.handshake(readCurrentKey());
} catch (BeaconClientException e) {
    if (e.getMessage().equals("Authentication failed")) {
        invalidateCachedKey();
        retryHandshakeWithFreshKey();
    } else throw e;
}

Prevention

When it happens

Trigger: Calling HandshakeExchange with request.getAuth() not matching the daemon's stored beacon auth key: wrong or stale key file, daemon re-generated its key, connecting to the wrong daemon instance, or omitting/corrupting the auth value.

Common situations: Multiple XPipe daemon versions/instances running and the client reading the wrong auth key; daemon restart regenerating credentials while a long-lived client caches the old key; copying a client between machines; permissions preventing the client from reading the key file.

Understand the failure class

Related errors


AI-assisted analysis of xpipe-io/xpipe@d85ca821ba (2026-09-06). Data as JSON: /api/errors/df84aa802dcab565. Report an issue: GitHub.