alibaba/open-code-review · error
unmarshal rule file %s: %w
Error message
unmarshal rule file %s: %w
What it means
loadRuleFile unmarshals the read project rule file into ProjectRule. This error wraps json.Unmarshal's failure and includes the file path: the file exists but its content is not valid JSON or doesn't match the ProjectRule schema.
Source
Thrown at internal/config/rules/system_rules.go:400
}
return nil, fmt.Errorf("read global rule %s: %w", path, err)
}
var pr ProjectRule
if err := json.Unmarshal(data, &pr); err != nil {
return nil, fmt.Errorf("unmarshal global rule: %w", err)
}
resolveRuleEntries(pr.Rules, filepath.Dir(path), "")
return &pr, nil
}
func loadRuleFile(path string) (*ProjectRule, error) {
data, err := os.ReadFile(path)
if err != nil {
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)View on GitHub (pinned to 5cf97d0d15)
Solutions
- Run jq . <path> to locate the syntax error and fix it
- Remove comments and any leading BOM; save as strict UTF-8 JSON matching ProjectRule's shape
- Ensure top level is an object with a rules field; validate the whole file before committing it to the repo
Example fix
// before (comments not allowed)
{
// project rules
"rules": []
}
// after
{
"rules": []
} Defensive patterns
Strategy: validation
Validate before calling
data, err := os.ReadFile(path)
if err != nil { return err }
if len(data) > 2 && data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {
return fmt.Errorf("%s has a UTF-8 BOM; save as plain UTF-8 JSON", path)
}
var v any
if err := json.Unmarshal(data, &v); err != nil {
return fmt.Errorf("%s is not valid JSON: %v", path, err)
} Try / catch
pr, err := loadRuleFile(path)
if err != nil {
if strings.Contains(err.Error(), "unmarshal rule file") {
var se *json.SyntaxError
if errors.As(err, &se) { // json.SyntaxError passes through %w
return fmt.Errorf("%s: JSON syntax at offset %d", path, se.Offset)
}
}
return err
} Prevention
- Validate .opencodereview/rule.json with jq before committing
- Editor setting: strip BOM, LF line endings, no comments
- Keep the file's top-level shape as an object with a rules field; lint it in CI
When it happens
Trigger: Valid read, failed json.Unmarshal — malformed JSON in <repoDir>/.opencodereview/rule.json (commas, comments — JSON has none —, truncated file), or wrong structure (array at top level, unexpected field types).
Common situations: Hand-edited project rule file with a syntax error; JSONC-style comments that strict encoding/json rejects; a file from another tool pasted into rule.json; CRLF/BOM issues from editors (a leading BOM breaks encoding/json).
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- read path_rule_map value for %q: %w
- unmarshal global rule: %w
- unmarshal task_template manifest: %w
- unmarshal default scan template: %w
- unmarshal tools file: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/1b803bbdeec2ad28.
Report an issue: GitHub.