{"record":{"id":"2fba74ed32484a42","repo":"JuliusBrussee/caveman","slug":"resolve-fixture-directory-w","errorCode":null,"errorMessage":"resolve fixture directory: %w","messagePattern":"resolve fixture directory: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/evals/harness.go","lineNumber":117,"sourceCode":"\tif err != nil {\n\t\treturn Report{}, fmt.Errorf(\"read manifest: %w\", err)\n\t}\n\tif err := yaml.Unmarshal(raw, &m); err != nil {\n\t\treturn Report{}, fmt.Errorf(\"parse manifest: %w\", err)\n\t}\n\tread := func(name string) ([]byte, error) {\n\t\treturn fixturesFS.ReadFile(\"fixtures/\" + name)\n\t}\n\treturn RunManifest(m, read)\n}\n\n// RunDir replays a caller-supplied fixture directory containing manifest.yaml.\n// Manifest file paths are slash-separated, relative, and confined to root even\n// through symlinks; a custom empty corpus is a configuration error, never green.\nfunc RunDir(root string) (Report, error) {\n\tresolvedRoot, err := filepath.EvalSymlinks(root)\n\tif err != nil {\n\t\treturn Report{}, fmt.Errorf(\"resolve fixture directory: %w\", err)\n\t}\n\tmanifestRaw, err := os.ReadFile(filepath.Join(resolvedRoot, \"manifest.yaml\"))\n\tif err != nil {\n\t\treturn Report{}, fmt.Errorf(\"read manifest: %w\", err)\n\t}\n\tvar m Manifest\n\tif err := yaml.Unmarshal(manifestRaw, &m); err != nil {\n\t\treturn Report{}, fmt.Errorf(\"parse manifest: %w\", err)\n\t}\n\tif len(m.Fixtures) == 0 {\n\t\treturn Report{}, fmt.Errorf(\"manifest has no fixtures\")\n\t}\n\tread := func(name string) ([]byte, error) {\n\t\tif !fs.ValidPath(name) || name == \".\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid fixture path %q\", name)\n\t\t}\n\t\tcandidate, err := filepath.EvalSymlinks(filepath.Join(resolvedRoot, filepath.FromSlash(name)))\n\t\tif err != nil {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/engine/evals/harness.go#L99-L135","documentation":"RunDir failed at filepath.EvalSymlinks(root): the fixture directory path does not exist, or a symlink in the path is broken/loops. Resolving the real path up front is how the harness confines fixture reads to the root, so an unresolvable root aborts before any fixture is opened.","triggerScenarios":"Calling evals.RunDir(root) with a typo'd path, a directory that was deleted, or a path containing a dangling/cyclic symlink.","commonSituations":"Passing a relative path from the wrong working directory; CI checkout layout changes so the fixtures dir moved; symlinked workspace (ln -s) pointing at a removed target.","solutions":["Check the path exists and the process can traverse it (ls, stat).","Use an absolute path or resolve relative to a known anchor (e.g. the test's working directory).","Fix or remove broken symlinks along the path.","If the directory moved after a repo restructure, update the --fixtures argument."],"exampleFix":"# before\nevals run --fixtures ./fixtures\n\n# after: absolute path\nevals run --fixtures \"$(pwd)/fixtures\"","handlingStrategy":"validation","validationCode":"func fixtureRootExists(root string) bool {\n    resolved, err := filepath.EvalSymlinks(root)\n    return err == nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass absolute fixture roots, e.g. via $(pwd) or runtime.Caller anchors.","Validate the path with os.Stat before invoking RunDir.","Avoid symlink chains into volatile locations (tmpdirs that get cleaned)."],"tags":["evals","filesystem","symlink","path"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}