alibaba/open-code-review · error
expected '{' in path_rule_map, got %v
Error message
expected '{' in path_rule_map, got %v What it means
SystemRule.UnmarshalJSON read the first token of path_rule_map successfully but it was not json.Delim('{') — the value is valid JSON yet not an object (e.g. an array, string, or number). The ordered-key streaming parser requires an object because it maps keys (glob patterns) to rule names in encounter order.
Source
Thrown at internal/config/rules/system_rules.go:67
// Use json.Decoder with UseNumber to preserve order of path_rule_map keys.
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
mapData, ok := raw["path_rule_map"]
if !ok || len(mapData) == 0 || string(mapData) == "null" {
return nil
}
// Parse ordered keys using a streaming decoder.
dec := json.NewDecoder(strings.NewReader(string(mapData)))
// Read opening '{'
t, err := dec.Token()
if err != nil {
return fmt.Errorf("expected '{' in path_rule_map: %w", err)
}
if t != json.Delim('{') {
return fmt.Errorf("expected '{' in path_rule_map, got %v", t)
}
for dec.More() {
// Read key
keyTok, err := dec.Token()
if err != nil {
return fmt.Errorf("read path_rule_map key: %w", err)
}
key, ok := keyTok.(string)
if !ok {
return fmt.Errorf("expected string key in path_rule_map, got %T", keyTok)
}
// Read value
var value string
if err := dec.Decode(&value); err != nil {
return fmt.Errorf("read path_rule_map value for %q: %w", key, err)
}
r.PathRules = append(r.PathRules, PathRule{Pattern: key, Rule: value})
}View on GitHub (pinned to 5cf97d0d15)
Solutions
- Change path_rule_map to a JSON object: {"<glob pattern>": "<rule file>", ...}
- Convert list-of-pairs form [{pattern, rule}] into a map form
- Check the config against the expected SystemRule schema for your version
- Run 'jq .path_rule_map' on the config — the output must be an object
Example fix
// before
"path_rule_map": [{"pattern": "*.go", "rule": "golang.md"}]
// after
"path_rule_map": {"*.go": "golang.md"} Defensive patterns
Strategy: validation
Validate before calling
func assertPathRuleMapObject(data []byte) error {
var probe struct {
PathRuleMap json.RawMessage `json:"path_rule_map"`
}
if err := json.Unmarshal(data, &probe); err != nil { return err }
if len(probe.PathRuleMap) == 0 || string(probe.PathRuleMap) == "null" { return nil }
var obj map[string]string
if err := json.Unmarshal(probe.PathRuleMap, &obj); err != nil {
return fmt.Errorf("path_rule_map must be an object: %w", err)
}
return nil
} Type guard
func isJSONObject(v json.RawMessage) bool {
return len(v) > 0 && strings.HasPrefix(strings.TrimSpace(string(v)), "{")
} Try / catch
if err := json.Unmarshal(cfgData, &systemRule); err != nil {
if strings.Contains(err.Error(), "expected '{' in path_rule_map") {
return fmt.Errorf("path_rule_map must be an object of {glob: ruleFile}: %w", err)
}
return err
} Prevention
- Document and enforce the schema: path_rule_map is {"<glob>": "<rule file>"}
- Convert legacy list-of-pairs configs to map form during config migration
- Validate with 'jq -e '.path_rule_map | type == "object"'
- Add a schema check to CI for custom rules files
When it happens
Trigger: path_rule_map set to a JSON array, string, number, or boolean in the rules config — e.g. "path_rule_map": ["*.go"] or "path_rule_map": "golang.md" — then the config is unmarshalled into SystemRule.
Common situations: Schema confusion after changing config format between versions; hand-written config using a list of objects instead of a map; YAML/JSON conversion tools that turned a map into a list of pairs.
Related errors
- expected '{' in path_rule_map: %w
- read path_rule_map key: %w
- expected string key in path_rule_map, got %T
- load rules: %w
- load config: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/dab6741635f9f521.
Report an issue: GitHub.