{"record":{"id":"4af72539a9502c97","repo":"agalwood/Motrix","slug":"plugin-fs-not-found","errorCode":"plugin.fs.not_found","errorMessage":"plugin.fs.not_found: ${relPath}","messagePattern":"plugin\\.fs\\.not_found: (.+?)","errorType":"exception","errorClass":"FsStorageError","httpStatus":null,"severity":"warning","filePath":"src/core/plugin/capabilities/fs-storage.ts","lineNumber":88,"sourceCode":"      const err = e as NodeJS.ErrnoException\n      if (err.code === 'ENOENT') return false\n      throw e\n    }\n  }\n\n  // -------------------------------------------------------------------------\n  // stat\n  // -------------------------------------------------------------------------\n\n  async stat(relPath: string): Promise<FsStorageStat> {\n    const abs = await resolveInsideSandbox(this.root, relPath)\n    let s: Awaited<ReturnType<typeof fs.stat>>\n    try {\n      s = await fs.stat(abs)\n    } catch (e: unknown) {\n      const err = e as NodeJS.ErrnoException\n      if (err.code === 'ENOENT') {\n        throw new FsStorageError(\n          'plugin.fs.not_found',\n          `plugin.fs.not_found: ${relPath}`\n        )\n      }\n      throw e\n    }\n    return {\n      size: s.size,\n      isFile: s.isFile(),\n      isDirectory: s.isDirectory(),\n      mtimeMs: s.mtimeMs,\n    }\n  }\n\n  // -------------------------------------------------------------------------\n  // read\n  // -------------------------------------------------------------------------\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/capabilities/fs-storage.ts#L70-L106","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst s = await storage.stat(rel) // throws if missing\n\n// after — treat missing as null\nasync function maybeStat(rel: string) {\n  try { return await storage.stat(rel) }\n  catch (e) { if (isFsCode(e, 'plugin.fs.not_found')) return null; throw e }\n}","handlingStrategy":"try-catch","validationCode":"async function exists(storage: FsStorage, rel: string): Promise<boolean> {\n  try { await storage.stat(rel); return true }\n  catch (e) { if ((e as FsStorageError).code === 'plugin.fs.not_found') return false; throw e }\n}","typeGuard":"function isNotFound(e: unknown): boolean {\n  return e instanceof Error && (e as FsStorageError).code === 'plugin.fs.not_found'\n}","tryCatchPattern":"try {\n  const s = await storage.stat(rel)\n} catch (e) {\n  if (isNotFound(e)) { /* treat as 'no such file' — return default/null */ }\n  else throw e\n}","preventionTips":["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."],"tags":["fs","storage","not-found","enoent"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}