xpipe-io/xpipe · error · BeaconClientException

Multiple stores found: " + storeNames

Error message

Multiple stores found: " + storeNames

What it means

Thrown by the beacon server when handling a /terminal/externalLaunch request: resolving the user-supplied connection input via DataStorageQuery.queryUserInput matched more than one data store, so the request is ambiguous and no single connection can be selected for the external terminal launch. It fires when the user's input (e.g. a name or partial identifier) is not unique across configured stores; the exception lists the matching store names so the caller can disambiguate.

Source

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

import java.util.List;

public class TerminalExternalLaunchExchange extends BeaconInterface<TerminalExternalLaunchExchange.Request> {

    @Override
    public String getPath() {
        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();
    }

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Use the fully qualified store path (category/connection) instead of the bare name
  2. Use the connection's UUID, which is unique
  3. Deduplicate/rename the connections so names are unique
  4. Narrow the query with a more specific path

Example fix

// before
client.terminalLaunch("webserver"); // matches 2 entries
// after
client.terminalLaunch("Servers/webserver"); // unique path
Defensive patterns

Strategy: validation

Validate before calling

var found = DataStorageQuery.queryUserInput(input);
if (found.size() > 1) throw new IllegalArgumentException("ambiguous: " + input);

Try / catch

try {
    client.terminalLaunch(input);
} catch (BeaconClientException ex) {
    if (ex.getMessage().startsWith("Multiple stores found")) {
        // retry with a fully-qualified path
    } else throw ex;
}

Prevention

When it happens

Trigger: Calling terminal/external launch with a partial or ambiguous 'connection' string (e.g. a bare name that exists in multiple categories, or a pattern matching several stores).

Common situations: Two connections with the same display name in different categories; passing a short name that also matches category names or multiple entries; duplicate imports of the same connection.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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