{"record":{"id":"4e9219d90c894c7f","repo":"alibaba/open-code-review","slug":"resolve-project-rule-s-w","errorCode":null,"errorMessage":"resolve project rule %s: %w","messagePattern":"resolve project rule (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/rules/system_rules.go","lineNumber":423,"sourceCode":"\n// loadProjectRule reads <repoDir>/.opencodereview/rule.json. Since #287 anchored\n// RepoDir at the git top-level, `ocr review` from a monorepo subdirectory loads\n// the repo-root rule file — which is consistent, since rule entries match against\n// root-relative diff paths. A subproject-local rule.json under the subdirectory is\n// intentionally not consulted; put shared rules at the repo root, or pass --rule.\nfunc loadProjectRule(repoDir string) (*ProjectRule, error) {\n\tconfineRoot, err := pathutil.CanonicalPath(repoDir)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"resolve repo dir %s: %w\", repoDir, err)\n\t}\n\n\tpath := filepath.Join(repoDir, \".opencodereview\", \"rule.json\")\n\tresolved, err := filepath.EvalSymlinks(path)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"resolve project rule %s: %w\", path, err)\n\t}\n\tif !pathutil.WithinBase(confineRoot, resolved) {\n\t\tfmt.Fprintf(os.Stderr, \"[ocr] WARNING: project rule file escapes repo dir: %s\\n\", path)\n\t\treturn nil, nil\n\t}\n\n\tdata, err := os.ReadFile(resolved)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"read project rule %s: %w\", path, err)\n\t}\n\tvar pr ProjectRule\n\tif err := json.Unmarshal(data, &pr); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal project rule: %w\", err)\n\t}\n\tresolveRuleEntries(pr.Rules, repoDir, confineRoot)","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/config/rules/system_rules.go#L405-L441","documentation":"After building the rule.json path, loadProjectRule calls filepath.EvalSymlinks to resolve symlinks. Any EvalSymlinks failure other than os.IsNotExist (permission problems, symlink loops, I/O errors) is wrapped as this error. A missing rule.json is intentionally not an error — nil is returned.","triggerScenarios":"filepath.EvalSymlinks on <repoDir>/.opencodereview/rule.json fails with a non-NotExist error: unreadable parent directory, dangling symlink with inaccessible components, ELOOP, or EACCES on traversal.","commonSituations":"A .opencodereview directory created by root with restrictive permissions while ocr runs as another user; a symlink chain pointing to a mounted volume that is offline; a broken symlink whose target path components are not listable.","solutions":["Check permissions on .opencodereview/ and its parents (chmod/chown so the ocr user can traverse)","Remove or repair the broken/dangling symlink at .opencodereview/rule.json","Read the wrapped EvalSymlinks error to identify the failing path component","If no project rule is needed, you can delete the .opencodereview/rule.json entry entirely"],"exampleFix":"// before\nls -l .opencodereview/rule.json   # dangling symlink\n// after\nrm .opencodereview/rule.json   # or ln -sf /real/path/rule.json .opencodereview/rule.json","handlingStrategy":"try-catch","validationCode":"func checkRuleSymlink(repoDir string) error {\n    p := filepath.Join(repoDir, \".opencodereview\", \"rule.json\")\n    fi, err := os.Lstat(p)\n    if os.IsNotExist(err) { return nil }\n    if err != nil { return err }\n    if fi.Mode()&os.ModeSymlink != 0 {\n        if _, err := filepath.EvalSymlinks(p); err != nil {\n            return fmt.Errorf(\"broken symlink %s: %w\", p, err)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"pr, err := loadProjectRule(repoDir)\nif err != nil {\n    if errors.Is(err, os.ErrPermission) {\n        fmt.Fprintln(os.Stderr, \"cannot access .opencodereview/rule.json: check permissions\")\n        os.Exit(2)\n    }\n    return err\n}","preventionTips":["Keep .opencodereview/ owned by the same user that runs ocr","Avoid symlink chains for rule.json; commit the real file","Ensure parent directories are world-executable (o+x) in shared CI images"],"tags":["go","filesystem","symlink","permissions"],"backgroundTag":"symlink-resolution-failed","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}