{"record":{"id":"1b803bbdeec2ad28","repo":"alibaba/open-code-review","slug":"unmarshal-rule-file-s-w","errorCode":null,"errorMessage":"unmarshal rule file %s: %w","messagePattern":"unmarshal rule file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/rules/system_rules.go","lineNumber":400,"sourceCode":"\t\t}\n\t\treturn nil, fmt.Errorf(\"read global 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 global rule: %w\", err)\n\t}\n\tresolveRuleEntries(pr.Rules, filepath.Dir(path), \"\")\n\treturn &pr, nil\n}\n\nfunc loadRuleFile(path string) (*ProjectRule, error) {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read rule file %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 rule file %s: %w\", path, err)\n\t}\n\tresolveRuleEntries(pr.Rules, filepath.Dir(path), \"\")\n\treturn &pr, nil\n}\n\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)","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/config/rules/system_rules.go#L382-L418","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","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"],"exampleFix":"// before (comments not allowed)\n{\n  // project rules\n  \"rules\": []\n}\n// after\n{\n  \"rules\": []\n}","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(path)\nif err != nil { return err }\nif len(data) > 2 && data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {\n\treturn fmt.Errorf(\"%s has a UTF-8 BOM; save as plain UTF-8 JSON\", path)\n}\nvar v any\nif err := json.Unmarshal(data, &v); err != nil {\n\treturn fmt.Errorf(\"%s is not valid JSON: %v\", path, err)\n}","typeGuard":null,"tryCatchPattern":"pr, err := loadRuleFile(path)\nif err != nil {\n\tif strings.Contains(err.Error(), \"unmarshal rule file\") {\n\t\tvar se *json.SyntaxError\n\t\tif errors.As(err, &se) { // json.SyntaxError passes through %w\n\t\t\treturn fmt.Errorf(\"%s: JSON syntax at offset %d\", path, se.Offset)\n\t\t}\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["json","config","unmarshal"],"backgroundTag":"json-parse-error","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}