ruvnet/ruflo · error

File not found

Error message

File not found

What it means

Thrown by safeReadFile() (v3/@claude-flow/hooks/src/workers/index.ts:158) when the underlying fs.stat/fs.readFile fails with code ENOENT; the helper rewrites it into a plain 'File not found' Error. It means the path you asked for does not exist on disk at read time.

Solutions

  1. Treat 'File not found' on first run as expected: catch it and initialize with an empty/default state instead of failing the hook.
  2. Verify the path exists beforehand (fs.access) or ensure the parent directory is created with fs.mkdir(dir, { recursive: true }) before the first write.
  3. Log the exact absolute path in the catch to spot cwd/separator mistakes.
  4. If the file should exist, check for cleanup jobs, container volume mounts, or CI steps removing it.

Example fix

// before
const content = await safeReadFile(this.persistPath, 1024 * 1024);

// after
let content: string;
try {
  content = await safeReadFile(this.persistPath, 1024 * 1024);
} catch (e) {
  if ((e as Error).message !== 'File not found') throw e;
  content = '{}'; // first run: no persisted state yet
}
Defensive patterns

Strategy: validation

Validate before calling

try {
  await fs.access(filePath);
} catch {
  // first run or cleaned state: use defaults instead of reading
  return defaultState;
}

Type guard

async function fileExists(p: string): Promise<boolean> {
  try { await fs.access(p); return true; } catch { return false; }
}

Try / catch

try {
  content = await safeReadFile(p);
} catch (e) {
  if ((e as Error).message === 'File not found') return defaultState;
  throw e;
}

Prevention

When it happens

Trigger: Reading a worker persistence file on first run before anything was written (persistPath never created); a race where the file is deleted between listing a directory and reading an entry; a typo'd or wrongly-resolved path (relative path resolved against an unexpected cwd).

Common situations: First-ever invocation of a session hook with no prior state; state directory cleaned by a cache clearer or CI step; path built from a config value with a wrong separator; file on a mounted volume that is not attached yet.

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 ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/e64eec3b0e61d232. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/hooks/src/workers/index.ts:158

    }
  }

  return content;
}

/**
 * Safe file read with size limit
 */
async function safeReadFile(filePath: string, maxSize = MAX_FILE_SIZE): Promise<string> {
  try {
    const stats = await fs.stat(filePath);
    if (stats.size > maxSize) {
      throw new Error(`File too large: ${stats.size} > ${maxSize}`);
    }
    return await fs.readFile(filePath, 'utf-8');
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
      throw new Error('File not found');
    }
    throw error;
  }
}

/**
 * Validate project root is a real directory
 */
async function validateProjectRoot(root: string): Promise<string> {
  const resolved = path.resolve(root);
  try {
    const stats = await fs.stat(resolved);
    if (!stats.isDirectory()) {
      throw new Error('Project root must be a directory');
    }
    return resolved;
  } catch {
    // If we can't validate, use cwd as fallback

View on GitHub (pinned to fa13ee4ad6)