paperclipai/paperclip · error
ENOENT
ENOENT
Error message
No such file: ${remotePath} What it means
ENOENT-contract emulation in the shell-backed sandbox filesystem client: readFile first runs `wc -c < remotePath` to bound chunked reads; when that shell command fails and the parent directory is confirmed searchable (so it is not a permission/transport problem), the client normalizes the failure to the same 'No such file' error the fs API would throw for an absent file. It is a deliberate sentinel mapping, not an unexpected crash.
Solutions
- Treat this error like fs ENOENT: check the remote path exists (correct cwd/absolute path) before reading.
- If the file should exist, verify it was created by an earlier step and the path spelling (case, separators) matches.
- For deletion races, re-check existence or tolerate absence in the caller before reading.
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at packages/adapter-utils/src/command-managed-runtime.ts:354 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/c3d9368dfd0eef69.
Report an issue: GitHub.
Appendix: source
Thrown at packages/adapter-utils/src/command-managed-runtime.ts:354
},
readFile: async (remotePath, options) => {
// Chunked reads intentionally query the remote size first, even without
// a progress sink, so each sandbox RPC stays bounded and truncation is
// detected without materializing the whole file as one stdout string.
let sizeResult;
try {
sizeResult = await runShell(`wc -c < ${shellQuote(remotePath)}`);
} catch (error) {
// Shell-backed sandbox reads need the same absent-file contract as fs.
// Confirm the parent is searchable so permission/transport failures are
// never silently converted into a missing optional credential file.
const parent = shellQuote(path.posix.dirname(remotePath));
const missing = await runShell(
`if [ -d ${parent} ] && [ -x ${parent} ] && [ ! -e ${shellQuote(remotePath)} ]; ` +
`then printf 'missing'; fi`,
).catch(() => null);
if (missing?.stdout === "missing") {
throw Object.assign(new Error(`No such file: ${remotePath}`), {
code: "ENOENT",
path: remotePath,
});
}
throw error;
}
const totalBytes = Number.parseInt(sizeResult.stdout.trim(), 10);
if (!Number.isFinite(totalBytes) || totalBytes < 0) {
throw new Error(`Could not determine remote file size for ${remotePath}`);
}
// Read in bounded remote chunks so the runner never has to materialize a
// single base64 stdout string for the whole archive. The client API still
// returns the decoded file as a Buffer, but every command result stays
// small enough for provider-backed sandbox RPCs.
const decodedChunks: Buffer[] = [];
let decodedSoFar = 0;
if (totalBytes === 0) {View on GitHub (pinned to 3f1d897a7c)