{"record":{"id":"1a40dfaf2adff938","repo":"ruvnet/ruflo","slug":"validation-failed-1a40df","errorCode":"VALIDATION_FAILED","errorMessage":"result.errors.join('; ')","messagePattern":"result\\.errors\\.join\\('; '\\)","errorType":"exception","errorClass":"PathValidatorError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/security/src/path-validator.ts","lineNumber":465,"sourceCode":"      resolvedPath,\n      relativePath,\n      matchedPrefix,\n      errors,\n    };\n  }\n\n  /**\n   * Validates and returns resolved path, throwing on failure.\n   *\n   * @param inputPath - The path to validate\n   * @returns Resolved path if valid\n   * @throws PathValidatorError if validation fails\n   */\n  async validateOrThrow(inputPath: string): Promise<string> {\n    const result = await this.validate(inputPath);\n\n    if (!result.isValid) {\n      throw new PathValidatorError(\n        result.errors.join('; '),\n        'VALIDATION_FAILED',\n        inputPath\n      );\n    }\n\n    return result.resolvedPath;\n  }\n\n  /**\n   * Synchronous validation (without symlink resolution).\n   *\n   * @param inputPath - The path to validate\n   * @returns Validation result\n   */\n  validateSync(inputPath: string): PathValidationResult {\n    const errors: string[] = [];\n","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/security/src/path-validator.ts#L447-L483","documentation":"validateOrThrow() is the throwing variant of validate(): it runs the full path check (allowed-prefix containment, blocked extensions/names, length, hidden-file rules, symlink resolution) and throws PathValidatorError VALIDATION_FAILED with all collected errors joined by '; ' when any check fails. The offending inputPath is attached to the error.","triggerScenarios":"Validating '/etc/passwd' when allowedPrefixes is ['/tmp']; accessing '.env' or a blocked name from DEFAULT_BLOCKED_NAMES; a path longer than maxPathLength (4096); a hidden dotfile when allowHidden is false (the default); a symlink whose realpath lands outside every prefix — the classic macOS os.tmpdir() -> /private/var case documented for #3010.","commonSituations":"Workspaces living under symlinked directories on macOS; agents legitimately trying to read .env (blocked by design); writing generated files with blocked extensions; moving a project into a path reachable only through symlinks.","solutions":["Parse the error message — each clause names the exact rule that failed, which tells you whether it is a prefix, extension, name, length, or symlink problem.","On macOS or symlinked deployments, add the realpath'd prefix (fs.realpathSync on your root) to allowedPrefixes, since the constructor pre-resolves prefixes but validate() canonicalizes candidates.","Switch to the non-throwing validate() call and branch on result.errors for expected denials.","If a blocked name/extension must be accessible in your context, override blockedNames/blockedExtensions in the constructor config deliberately."],"exampleFix":"// before\nconst safe = await validator.validateOrThrow(userPath); // throws on .env or symlink escapes\n\n// after\nconst result = await validator.validate(userPath);\nif (!result.isValid) return { allowed: false, reasons: result.errors };\nconst safe = result.resolvedPath;","handlingStrategy":"validation","validationCode":"const result = await validator.validate(inputPath);\nif (!result.isValid) {\n  return { allowed: false, reasons: result.errors }; // graceful branch\n}\nconst safePath = result.resolvedPath;","typeGuard":null,"tryCatchPattern":"try {\n  return await validator.validateOrThrow(inputPath);\n} catch (err) {\n  if (err instanceof PathValidatorError && err.code === 'VALIDATION_FAILED') {\n    throw new ForbiddenAccess(err.message, { path: inputPath });\n  }\n  throw err;\n}","preventionTips":["Prefer validate() over validateOrThrow() for user-supplied paths — denial is an expected outcome, not an exception.","On macOS/symlinked layouts, feed fs.realpath'd workspace roots as allowedPrefixes (see #3010).","Log result.errors verbatim; each clause names the exact rule (prefix/extension/name/length/hidden) that tripped."],"tags":["path","symlink","security","validation"],"backgroundTag":"path-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}