{"record":{"id":"e64eec3b0e61d232","repo":"ruvnet/ruflo","slug":"file-not-found-e64eec","errorCode":null,"errorMessage":"File not found","messagePattern":"File not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/hooks/src/workers/index.ts","lineNumber":158,"sourceCode":"    }\n  }\n\n  return content;\n}\n\n/**\n * Safe file read with size limit\n */\nasync function safeReadFile(filePath: string, maxSize = MAX_FILE_SIZE): Promise<string> {\n  try {\n    const stats = await fs.stat(filePath);\n    if (stats.size > maxSize) {\n      throw new Error(`File too large: ${stats.size} > ${maxSize}`);\n    }\n    return await fs.readFile(filePath, 'utf-8');\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n      throw new Error('File not found');\n    }\n    throw error;\n  }\n}\n\n/**\n * Validate project root is a real directory\n */\nasync function validateProjectRoot(root: string): Promise<string> {\n  const resolved = path.resolve(root);\n  try {\n    const stats = await fs.stat(resolved);\n    if (!stats.isDirectory()) {\n      throw new Error('Project root must be a directory');\n    }\n    return resolved;\n  } catch {\n    // If we can't validate, use cwd as fallback","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/hooks/src/workers/index.ts#L140-L176","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Treat 'File not found' on first run as expected: catch it and initialize with an empty/default state instead of failing the hook.","Verify the path exists beforehand (fs.access) or ensure the parent directory is created with fs.mkdir(dir, { recursive: true }) before the first write.","Log the exact absolute path in the catch to spot cwd/separator mistakes.","If the file should exist, check for cleanup jobs, container volume mounts, or CI steps removing it."],"exampleFix":"// before\nconst content = await safeReadFile(this.persistPath, 1024 * 1024);\n\n// after\nlet content: string;\ntry {\n  content = await safeReadFile(this.persistPath, 1024 * 1024);\n} catch (e) {\n  if ((e as Error).message !== 'File not found') throw e;\n  content = '{}'; // first run: no persisted state yet\n}","handlingStrategy":"validation","validationCode":"try {\n  await fs.access(filePath);\n} catch {\n  // first run or cleaned state: use defaults instead of reading\n  return defaultState;\n}","typeGuard":"async function fileExists(p: string): Promise<boolean> {\n  try { await fs.access(p); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  content = await safeReadFile(p);\n} catch (e) {\n  if ((e as Error).message === 'File not found') return defaultState;\n  throw e;\n}","preventionTips":["Create parent directories with mkdir(recursive: true) before first write.","Treat missing state on first run as normal, not an error.","Use absolute paths built from a single constant to avoid cwd-dependent resolution."],"tags":["file-not-found","filesystem","enoent"],"backgroundTag":"file-not-found","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}