agalwood/Motrix · warning · FsStorageError
plugin.fs.not_found
plugin.fs.not_found
Error message
plugin.fs.not_found: ${relPath} What it means
Thrown by FsStorage.stat() when the underlying `fs.stat` fails with ENOENT after the sandbox resolver accepted the path. The path was in-bounds but pointed at nothing on disk. Code is `plugin.fs.not_found`. Note the relPath (caller-supplied) is interpolated into the message, not the resolved absolute path.
Source
Thrown at src/core/plugin/capabilities/fs-storage.ts:88
const err = e as NodeJS.ErrnoException
if (err.code === 'ENOENT') return false
throw e
}
}
// -------------------------------------------------------------------------
// stat
// -------------------------------------------------------------------------
async stat(relPath: string): Promise<FsStorageStat> {
const abs = await resolveInsideSandbox(this.root, relPath)
let s: Awaited<ReturnType<typeof fs.stat>>
try {
s = await fs.stat(abs)
} catch (e: unknown) {
const err = e as NodeJS.ErrnoException
if (err.code === 'ENOENT') {
throw new FsStorageError(
'plugin.fs.not_found',
`plugin.fs.not_found: ${relPath}`
)
}
throw e
}
return {
size: s.size,
isFile: s.isFile(),
isDirectory: s.isDirectory(),
mtimeMs: s.mtimeMs,
}
}
// -------------------------------------------------------------------------
// read
// -------------------------------------------------------------------------
View on GitHub (pinned to 1a708ee577)
Solutions
- Check existence with stat and handle not_found as an expected branch (e.g. return a default) rather than propagating.
- Verify the relPath spelling and that the file was written to the same sandbox root.
- If racing a write, retry with backoff or await the writer's completion signal before stating.
- Use a higher-level existence helper that swallows not_found and returns null.
Example fix
// before
const s = await storage.stat(rel) // throws if missing
// after — treat missing as null
async function maybeStat(rel: string) {
try { return await storage.stat(rel) }
catch (e) { if (isFsCode(e, 'plugin.fs.not_found')) return null; throw e }
} Defensive patterns
Strategy: try-catch
Validate before calling
async function exists(storage: FsStorage, rel: string): Promise<boolean> {
try { await storage.stat(rel); return true }
catch (e) { if ((e as FsStorageError).code === 'plugin.fs.not_found') return false; throw e }
} Type guard
function isNotFound(e: unknown): boolean {
return e instanceof Error && (e as FsStorageError).code === 'plugin.fs.not_found'
} Try / catch
try {
const s = await storage.stat(rel)
} catch (e) {
if (isNotFound(e)) { /* treat as 'no such file' — return default/null */ }
else throw e
} Prevention
- Wrap stat in an existence helper that returns null on not_found.
- Await writer completion before stating its output.
- Treat not_found as an expected branch, not a fatal error.
When it happens
Trigger: Calling `storage.stat(relPath)` for a file that does not exist (typo, deleted, never written, race with delete). Distinct from path_outside_sandbox, which would have thrown earlier.
Common situations: Plugin assumes a file written by another plugin/step exists; eventual consistency where stat races a just-finished write; wrong relative path computed; test against an empty sandbox.
Related errors
- plugin.fs.not_a_file
- plugin.fs.overwrite_required
- TaskNotFound
- plugin.fs.path_too_long
- plugin.fs.path_outside_sandbox
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/4af72539a9502c97.
Report an issue: GitHub.