{"record":{"id":"5b5bf3f6793a52ae","repo":"alibaba/open-code-review","slug":"unmarshal-project-rule-w","errorCode":null,"errorMessage":"unmarshal project rule: %w","messagePattern":"unmarshal project rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/rules/system_rules.go","lineNumber":439,"sourceCode":"\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)\n\treturn &pr, nil\n}\n\n// Resolve checks each layer in priority order; first match wins. User rules\n// replace the system rule by default; rules with merge_system_rule keep the\n// matched system rule alongside the user rule.\nfunc (c *composedResolver) Resolve(path string) string {\n\tfor _, layer := range []*ProjectRule{c.custom, c.project, c.global} {\n\t\tif entry := matchProjectRuleEntry(layer, path); entry != nil {\n\t\t\tif entry.MergeSystemRule {\n\t\t\t\treturn c.mergeWithSystemRule(path, entry.Rule)\n\t\t\t}\n\t\t\treturn entry.Rule\n\t\t}\n\t}\n\treturn c.system.Resolve(path)","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/config/rules/system_rules.go#L421-L457","documentation":"The rule.json contents are unmarshaled into ProjectRule with encoding/json. Any JSON syntax or type error (trailing commas, unquoted keys, wrong types for fields) produces this wrapped error. Unlike earlier failures there is no NotExist escape — a present but invalid rule file always fails the resolver.","triggerScenarios":"json.Unmarshal of .opencodereview/rule.json fails because the file is not valid JSON or fields in ProjectRule have mismatched types (e.g. \"rules\": \"x\" instead of an array).","commonSituations":"Hand-edited rule.json with a missing comma or comment (JSON has no comments); a rule file copied from YAML; an editor that saved a BOM or truncated the file; schema drift after upgrading ocr to a version with stricter types.","solutions":["Validate the JSON: `jq . .opencodereview/rule.json` or paste into a JSON linter","Remove comments/trailing commas — rule.json must be strict JSON","Check field types match the ProjectRule struct (rules must be an array of objects)","Re-copy a known-good rule.json from the repo template"],"exampleFix":"// before (rule.json)\n{ \"rules\": [ { \"id\": \"r1\", } ] }   // trailing comma\n// after\n{ \"rules\": [ { \"id\": \"r1\" } ] }","handlingStrategy":"validation","validationCode":"func validateRuleJSON(path string) error {\n    data, err := os.ReadFile(path)\n    if err != nil { return err }\n    var pr rules.ProjectRule\n    if err := json.Unmarshal(data, &pr); err != nil {\n        return fmt.Errorf(\"%s: invalid JSON: %w\", path, err)\n    }\n    return nil\n}\n// run in CI: go run ./cmd/validate-rule .opencodereview/rule.json","typeGuard":null,"tryCatchPattern":"pr, err := loadProjectRule(repoDir)\nif err != nil {\n    var syn *json.SyntaxError\n    if errors.As(err, &syn) {\n        fmt.Fprintf(os.Stderr, \"JSON syntax error at offset %d: %v\\n\", syn.Offset, syn)\n    }\n    return err\n}","preventionTips":["Lint rule.json with `jq .` in pre-commit hooks","Never put comments or trailing commas in rule.json","Validate after every hand edit: `jq empty .opencodereview/rule.json`","Keep a schema-checked template of rule.json in the repo"],"tags":["go","json","config","schema"],"backgroundTag":"json-parse-error","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}