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

  1. Check existence with stat and handle not_found as an expected branch (e.g. return a default) rather than propagating.
  2. Verify the relPath spelling and that the file was written to the same sandbox root.
  3. If racing a write, retry with backoff or await the writer's completion signal before stating.
  4. 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

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


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/4af72539a9502c97. Report an issue: GitHub.