xpipe-io/xpipe · error · BeaconClientException

Connection " + DataStorage.get().getStorePath(e).toString()

Error message

Connection " + DataStorage.get().getStorePath(e).toString() + " is not a shell connection

What it means

After a unique connection is resolved, the exchange checks that its DataStore implements ShellStore. Non-shell connections cannot be opened in an external terminal as a shell, so the handler throws with the full store path for clarity.

Source

Thrown at app/src/main/java/io/xpipe/app/beacon/api/TerminalExternalLaunchExchange.java:44

        return "/terminal/externalLaunch";
    }

    @Override
    public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException, BeaconServerException {
        var found = DataStorageQuery.queryUserInput(msg.getConnection());
        if (found.isEmpty()) {
            throw new BeaconClientException("No connection found for input " + msg.getConnection());
        }

        if (found.size() > 1) {
            throw new BeaconClientException("Multiple stores found: "
                    + found.stream().map(DataStoreEntry::getName).toList());
        }

        var e = found.getFirst();
        var isShell = e.getStore() instanceof ShellStore;
        if (!isShell) {
            throw new BeaconClientException(
                    "Connection " + DataStorage.get().getStorePath(e).toString() + " is not a shell connection");
        }

        if (!checkPermission()) {
            return Response.builder().command(List.of()).build();
        }

        var r = TerminalLauncherManager.externalExchange(e.ref(), msg.getArguments());
        return Response.builder().command(r).build();
    }

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

    @Override
    public Object getSynchronizationObject() {

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Target the shell sub-connection of the store (e.g. the SSH child) rather than the parent
  2. Check e.getStore() instanceof ShellStore before launching
  3. Use the shell/start API for shell session management instead of external launch
  4. Create a shell-capable connection for the host you need

Example fix

// before
client.terminalLaunch("my-database"); // not a shell
// after
if (entry.getStore() instanceof ShellStore) {
    client.terminalLaunch(entry.getUuid());
} else {
    client.terminalLaunch("my-database/ssh"); // shell child
}
Defensive patterns

Strategy: type-guard

Validate before calling

DataStoreEntry e = found.getFirst();
if (!(e.getStore() instanceof ShellStore)) throw new IllegalArgumentException("not a shell: " + e.getName());

Type guard

static boolean isShell(DataStoreEntry e) {
    return e.getStore() instanceof ShellStore;
}

Try / catch

try {
    client.terminalLaunch(input);
} catch (BeaconClientException ex) {
    if (ex.getMessage().contains("is not a shell connection")) {
        // target a shell sub-connection instead
    } else throw ex;
}

Prevention

When it happens

Trigger: Calling terminal/external launch with a connection whose store is not a ShellStore — e.g. a script, vault, data-store (database), or custom store entry.

Common situations: Scripts pick the first search result without checking its type; user passes a database or script connection where a shell was expected; a connection that previously hosted a shell sub-connection was targeted directly instead of its shell child.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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