alibaba/open-code-review · error
resolve project rule %s: %w
Error message
resolve project rule %s: %w
What it means
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.
Source
Thrown at internal/config/rules/system_rules.go:423
// loadProjectRule reads <repoDir>/.opencodereview/rule.json. Since #287 anchored
// RepoDir at the git top-level, `ocr review` from a monorepo subdirectory loads
// the repo-root rule file — which is consistent, since rule entries match against
// root-relative diff paths. A subproject-local rule.json under the subdirectory is
// intentionally not consulted; put shared rules at the repo root, or pass --rule.
func loadProjectRule(repoDir string) (*ProjectRule, error) {
confineRoot, err := pathutil.CanonicalPath(repoDir)
if err != nil {
return nil, fmt.Errorf("resolve repo dir %s: %w", repoDir, err)
}
path := filepath.Join(repoDir, ".opencodereview", "rule.json")
resolved, err := filepath.EvalSymlinks(path)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("resolve project rule %s: %w", path, err)
}
if !pathutil.WithinBase(confineRoot, resolved) {
fmt.Fprintf(os.Stderr, "[ocr] WARNING: project rule file escapes repo dir: %s\n", path)
return nil, nil
}
data, err := os.ReadFile(resolved)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("read project rule %s: %w", path, err)
}
var pr ProjectRule
if err := json.Unmarshal(data, &pr); err != nil {
return nil, fmt.Errorf("unmarshal project rule: %w", err)
}
resolveRuleEntries(pr.Rules, repoDir, confineRoot)View on GitHub (pinned to 5cf97d0d15)
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
Example fix
// before ls -l .opencodereview/rule.json # dangling symlink // after rm .opencodereview/rule.json # or ln -sf /real/path/rule.json .opencodereview/rule.json
Defensive patterns
Strategy: try-catch
Validate before calling
func checkRuleSymlink(repoDir string) error {
p := filepath.Join(repoDir, ".opencodereview", "rule.json")
fi, err := os.Lstat(p)
if os.IsNotExist(err) { return nil }
if err != nil { return err }
if fi.Mode()&os.ModeSymlink != 0 {
if _, err := filepath.EvalSymlinks(p); err != nil {
return fmt.Errorf("broken symlink %s: %w", p, err)
}
}
return nil
} Try / catch
pr, err := loadProjectRule(repoDir)
if err != nil {
if errors.Is(err, os.ErrPermission) {
fmt.Fprintln(os.Stderr, "cannot access .opencodereview/rule.json: check permissions")
os.Exit(2)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- read project rule %s: %w
- resolve file %q: %w
- read background file %q: %w
- background file %q is a directory, not a file
- load config: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/4e9219d90c894c7f.
Report an issue: GitHub.