xpipe-io/xpipe · error · BeaconClientException

Not a shell connection

Error message

Not a shell connection

What it means

XPipe's beacon HTTP API throws this when a client requests a shell action (shell/start) against a store entry whose underlying DataStore is not a ShellStore. Only connections that actually provide a shell (SSH, local shell, etc.) can start shell sessions, so the handler rejects non-shell stores early with a typed BeaconClientException.

Source

Thrown at app/src/main/java/io/xpipe/app/beacon/api/ShellStartExchange.java:36

import lombok.extern.jackson.Jacksonized;

import java.util.UUID;

public class ShellStartExchange extends BeaconInterface<ShellStartExchange.Request> {

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

    @Override
    @SneakyThrows
    public Object handle(HttpExchange exchange, Request msg) {
        var e = DataStorage.get()
                .getStoreEntryIfPresent(msg.getStore())
                .orElseThrow(() -> new BeaconClientException("Unknown connection"));
        if (!(e.getStore() instanceof ShellStore s)) {
            throw new BeaconClientException("Not a shell connection");
        }

        var existing = AppBeaconServer.get().getCache().getShellSessions().stream()
                .filter(beaconShellSession -> beaconShellSession.getEntry().equals(e))
                .findFirst();
        var control = (existing.isPresent()
                ? existing.get().getControl()
                : s.standaloneControl().start());
        control.setNonInteractive();
        control.start();

        var d = control.getShellDialect().getDumbMode();
        if (!d.supportsAnyPossibleInteraction()) {
            control.close();
            d.throwIfUnsupported();
        }

        if (existing.isEmpty()) {

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Verify the connection is a shell-type connection (SSH, local, WSL, docker, etc.) in the XPipe UI before targeting it
  2. Check the store type client-side before calling: e instanceof ShellStore or inspect the store's type in the listing response
  3. Use the correct beacon endpoint for the store kind you actually have
  4. If you need a shell on a non-shell store, add a shell-capable sub-connection to it and target that instead

Example fix

// before
client.shellStart(storeUuid); // store may not be a shell
// after
DataStoreEntry e = DataStorage.get().getStoreEntry(storeUuid);
if (e.getStore() instanceof ShellStore) {
    client.shellStart(storeUuid);
} else {
    throw new IllegalArgumentException(storeUuid + " is not a shell connection");
}
Defensive patterns

Strategy: type-guard

Validate before calling

DataStoreEntry e = DataStorage.get().getStoreEntryIfPresent(uuid).orElse(null);
boolean ok = e != null && e.getStore() instanceof ShellStore;

Type guard

static boolean isShellConnection(DataStoreEntry e) {
    return e != null && e.getStore() instanceof ShellStore;
}

Try / catch

try {
    client.shellStart(req);
} catch (BeaconClientException ex) {
    if (ex.getMessage().contains("Not a shell connection")) {
        // fall back to a different connection or skip
    } else throw ex;
}

Prevention

When it happens

Trigger: Calling the POST /shell/start beacon endpoint (ShellStartExchange.handle) with a store UUID whose DataStore does not implement ShellStore, e.g. a script group, custom store, or category-like entry.

Common situations: Automation scripts iterate over all connections and blindly call shell start on every store; users pass the UUID of a non-shell connection; a store type changed after an update so a previously shell-capable store no longer is.

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/a22d20384c929fec. Report an issue: GitHub.