alibaba/open-code-review · error

resolve repo dir %s: %w

Error message

resolve repo dir %s: %w

What it means

loadProjectRule first canonicalizes the repository directory via pathutil.CanonicalPath before locating .opencodereview/rule.json. If that canonicalization fails (e.g. the path cannot be made absolute/clean because the directory is missing or the path is malformed), the error is wrapped with the repo dir for context. It is thrown by NewResolver during resolver construction, so review runs abort early.

Source

Thrown at internal/config/rules/system_rules.go:414

		return nil, fmt.Errorf("read rule file %s: %w", path, err)
	}
	var pr ProjectRule
	if err := json.Unmarshal(data, &pr); err != nil {
		return nil, fmt.Errorf("unmarshal rule file %s: %w", path, err)
	}
	resolveRuleEntries(pr.Rules, filepath.Dir(path), "")
	return &pr, nil
}

// 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) {

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Run the tool from inside an existing git repository or pass --repo with a valid absolute directory
  2. Check that the repo dir actually exists before invoking ocr (e.g. `ls <repoDir>`)
  3. Inspect the wrapped inner error (%w) from pathutil.CanonicalPath to see the root cause

Example fix

// before
ocr review --repo ./rpovider-service
// after
ocr review --repo ./provider-service
Defensive patterns

Strategy: validation

Validate before calling

import "path/filepath"
func ensureRepoDir(dir string) error {
    if dir == "" { return fmt.Errorf("repo dir is empty") }
    abs, err := filepath.Abs(dir)
    if err != nil { return err }
    info, err := os.Stat(abs)
    if err != nil { return fmt.Errorf("repo dir %s: %w", abs, err) }
    if !info.IsDir() { return fmt.Errorf("%s is not a directory", abs) }
    return nil
}

Try / catch

rule, err := rules.NewResolver(repoDir)
if err != nil {
    var pathErr *os.PathError
    if errors.As(err, &pathErr) {
        fmt.Fprintf(os.Stderr, "bad repo dir %s: %v\n", pathErr.Path, pathErr.Err)
        os.Exit(2)
    }
    return err
}

Prevention

When it happens

Trigger: NewResolver is invoked with a --repo or repoDir value that CanonicalPath cannot resolve: an empty path, a nonexistent directory, or a path that fails the underlying transformation.

Common situations: Running `ocr review` outside a git repo so the detected repo dir is empty; passing a typo'd --repo flag; a CI checkout that has not happened yet so the target dir does not exist.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/03e5d465d9615b7a. Report an issue: GitHub.