xpipe-io/xpipe · error · BeaconClientException

Directory ${path} does not exist

Error message

Directory ${path} does not exist

What it means

The MCP listFiles tool checks fs.directoryExists(path) on the target shell before enumerating; if the path is not an existing directory it throws this BeaconClientException with the resolved path. This also fires when the path exists but is a regular file, since it must be a directory.

Source

Thrown at app/src/main/java/io/xpipe/app/beacon/mcp/McpTools.java:244

                                .build();
                    }
                }))
                .build();
    }

    public static McpServerFeatures.SyncToolSpecification listFiles() throws IOException {
        var tool = McpSchemaFiles.loadTool("list_files.json");
        return McpServerFeatures.SyncToolSpecification.builder()
                .tool(tool)
                .callHandler(McpToolHandler.of((req) -> {
                    var system = req.getStringArgument("system");
                    var shellStore = req.getShellStoreRef(system, false);
                    var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
                    var fs = new ShellFileSystem(shellSession.getControl());
                    var path = req.getFilePath(shellSession.getControl(), "path");

                    if (!fs.directoryExists(path)) {
                        throw new BeaconClientException("Directory " + path + " does not exist");
                    }

                    try (var stream = fs.listFiles(fs, path)) {
                        var list = stream.toList();
                        var builder = McpSchema.CallToolResult.builder();
                        for (FileEntry e : list) {
                            builder.addTextContent(e.getPath().toString());
                        }
                        return builder.build();
                    }
                }))
                .build();
    }

    public static McpServerFeatures.SyncToolSpecification findFile() throws IOException {
        var tool = McpSchemaFiles.loadTool("find_file.json");
        return McpServerFeatures.SyncToolSpecification.builder()
                .tool(tool)

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Verify the directory exists on that connection (e.g. readFile a known file or run an ls via another tool) before listing
  2. Use an absolute directory path rather than a relative or '~'-based guess
  3. If the path is a file, read it with readFile instead of listing it
  4. Catch BeaconClientException and fall back to listing the parent directory to discover the correct name

Example fix

// before
{"system": "my-ssh", "path": "~/logs"} // directory absent
// after
{"system": "my-ssh", "path": "/var/log"}
Defensive patterns

Strategy: validation

Validate before calling

// verify the path is an existing directory before listing
const parent = path.substring(0, path.lastIndexOf('/')) || '/';
const entries = await listFiles(system, parent); // throws if parent missing
const target = entries.find(e => e.path === path);
if (!target || !target.isDirectory) {
  throw new Error(`'${path}' is not a directory on '${system}'`);
}

Type guard

function isDirectoryEntry(e) { return e != null && e.isDirectory === true; }

Try / catch

try { return listFiles(system, path); } catch (BeaconClientException e) { if (e.message.includes('does not exist')) { /* fall back to listing the parent or reading as a file */ } throw e; }

Prevention

When it happens

Trigger: Calling the MCP listFiles tool with a 'path' that is missing on the shell, or that points to a regular file instead of a directory; tilde-expanded path resolved against the connection user's home.

Common situations: Listing '~' paths whose home differs from expectation; pointing at a file (e.g. /etc/hosts) rather than a directory; directory removed or renamed on the remote; wrong connection selected.

Related errors


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