xpipe-io/xpipe · error · BeaconClientException

File does not exist

Error message

File ${path} does not exist

What it means

The MCP readFile tool opens a ShellFileSystem on the target shell and checks fs.fileExists(path) before reading; if the file is absent it throws this BeaconClientException including the resolved path (tilde already expanded against the user home). This is a pre-flight existence check, not an I/O failure.

Solutions

  1. Verify the file exists via the listFiles tool or an ls call on the same connection before reading
  2. Use an absolute path to remove working-directory ambiguity
  3. Check path casing exactly; Linux shells are case-sensitive
  4. Catch BeaconClientException and fall back to listing the parent directory to find the correct name

Example fix

// before
{"system": "my-ssh", "path": "~/Config/app.conf"} // file absent
// after: confirm with listFiles on the parent directory, then
{"system": "my-ssh", "path": "~/config/app.conf"}
Defensive patterns

Strategy: validation

Validate before calling

// existence check via listFiles before reading
const parent = path.substring(0, path.lastIndexOf('/')) || '/';
const entries = await listFiles(system, parent);
if (!entries.some(e => e.path === path)) {
  throw new Error(`file '${path}' not found on '${system}'`);
}

Try / catch

try { return readFile(system, path); } catch (BeaconClientException e) { if (e.message.includes('does not exist')) { /* list parent directory and retry with corrected path */ } throw e; }

Prevention

When it happens

Trigger: Calling the MCP readFile tool with a 'path' that does not exist on the remote/local shell filesystem: typo, wrong relative base, file deleted, or case-mismatch on case-sensitive filesystems.

Common situations: Assuming the working directory differs from the shell's actual home; case-sensitive Linux paths vs case-insensitive local dev; referencing a file on the wrong connection (file exists on another host).

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

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

                                    JacksonMapper.getDefault().writeValueAsString(object))
                            .build();
                }))
                .build();
    }

    public static McpServerFeatures.SyncToolSpecification readFile() throws IOException {
        var tool = McpSchemaFiles.loadTool("read_file.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 path = req.getFilePath(shellSession.getControl(), "path");
                    var fs = new ShellFileSystem(shellSession.getControl());

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

                    try (var in = fs.openInput(path)) {
                        var b = in.readAllBytes();
                        var s = new String(b, StandardCharsets.UTF_8);
                        return McpSchema.CallToolResult.builder()
                                .addTextContent(s)
                                .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) -> {

View on GitHub (pinned to d85ca821ba)