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
- Re-read the current beacon auth key from the daemon's key file location and retry the handshake
- Confirm you are connecting to the intended daemon instance/port (not another local daemon)
- Restart the client so it performs a fresh handshake instead of reusing a cached key
- 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
- Always read the auth key fresh from the daemon's key file instead of caching
- Verify daemon port/pid so you don't handshake with the wrong instance
- Ensure the client process has read permission on the key file
- Re-handshake after daemon restarts
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Cannot delete category: " + cat.getName()
- Unsupported mode: " + msg.getMode().getDisplayName() + ". Su
- File path " + msg.getPath() + " is not absolute
- File " + msg.getPath() + " does not exist
- File path " + msg.getPath() + " is not absolute
AI-assisted analysis of xpipe-io/xpipe@d85ca821ba (2026-09-06).
Data as JSON: /api/errors/df84aa802dcab565.
Report an issue: GitHub.