{"record":{"id":"7fabd074fa0d85ba","repo":"alibaba/open-code-review","slug":"expected-string-key-in-path-rule-map-got-t","errorCode":null,"errorMessage":"expected string key in path_rule_map, got %T","messagePattern":"expected string key in path_rule_map, got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/rules/system_rules.go","lineNumber":77,"sourceCode":"\t// Parse ordered keys using a streaming decoder.\n\tdec := json.NewDecoder(strings.NewReader(string(mapData)))\n\t// Read opening '{'\n\tt, err := dec.Token()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"expected '{' in path_rule_map: %w\", err)\n\t}\n\tif t != json.Delim('{') {\n\t\treturn fmt.Errorf(\"expected '{' in path_rule_map, got %v\", t)\n\t}\n\tfor dec.More() {\n\t\t// Read key\n\t\tkeyTok, err := dec.Token()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read path_rule_map key: %w\", err)\n\t\t}\n\t\tkey, ok := keyTok.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected string key in path_rule_map, got %T\", keyTok)\n\t\t}\n\t\t// Read value\n\t\tvar value string\n\t\tif err := dec.Decode(&value); err != nil {\n\t\t\treturn fmt.Errorf(\"read path_rule_map value for %q: %w\", key, err)\n\t\t}\n\t\tr.PathRules = append(r.PathRules, PathRule{Pattern: key, Rule: value})\n\t}\n\treturn nil\n}\n\n//go:embed system_rules.json rule_docs/*\nvar rulesFS embed.FS\n\n// LoadDefault parses the embedded system_rules.json and resolves rule file references.\nfunc LoadDefault() (*SystemRule, error) {\n\tdata, err := rulesFS.ReadFile(\"system_rules.json\")\n\tif err != nil {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/config/rules/system_rules.go#L59-L95","documentation":"The ordered path_rule_map parser read a key token that was not a JSON string. JSON technically only allows string keys, so reaching this usually means the streaming decoder produced a non-string token (e.g. after malformed input such as an unquoted key or a stray value where a key was expected), or the decoder state desynced. The error reports the Go type of the offending token (%T) for diagnosis.","triggerScenarios":"path_rule_map contains an unquoted/invalid key so the token stream yields a non-string token where a key belongs — e.g. {*.go: \"golang.md\"} or {123: \"rule.md\"} — during SystemRule unmarshalling.","commonSituations":"Hand-edited configs forgetting quotes around glob patterns; YAML-to-JSON converters emitting numeric keys; generator scripts interpolating keys without quoting.","solutions":["Quote every key in path_rule_map as a JSON string: \"*.go\" not *.go","Validate with 'jq .' — it rejects unquoted keys and points at the line","Regenerate the config from a schema/template that quotes keys","If keys must be non-strings upstream, stringify them before writing the JSON"],"exampleFix":"// before\n{\"*.go\": \"golang.md\", 42: \"misc.md\"}\n// after\n{\"*.go\": \"golang.md\", \"42\": \"misc.md\"}","handlingStrategy":"validation","validationCode":"func keysAreStrings(data []byte) error {\n    dec := json.NewDecoder(bytes.NewReader(data))\n    if _, err := dec.Token(); err != nil { return err }\n    for dec.More() {\n        tok, err := dec.Token()\n        if err != nil { return err }\n        if _, ok := tok.(string); !ok {\n            return fmt.Errorf(\"non-string key token %T\", tok)\n        }\n        var v json.RawMessage\n        if err := dec.Decode(&v); err != nil { return err }\n    }\n    return nil\n}","typeGuard":"func allKeysQuoted(raw string) bool {\n    // strip the braces; every key must start with '\"'\n    inner := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(raw), \"{\"), \"}\"))\n    if inner == \"\" { return true }\n    for _, part := range strings.Split(inner, \",\") {\n        if !strings.HasPrefix(strings.TrimSpace(part), \"\\\"\") { return false }\n    }\n    return true\n}","tryCatchPattern":"if err := json.Unmarshal(data, &rule); err != nil {\n    if strings.Contains(err.Error(), \"expected string key in path_rule_map\") {\n        return fmt.Errorf(\"quote every glob key in path_rule_map: %w\", err)\n    }\n    return err\n}","preventionTips":["Always double-quote keys in path_rule_map, including patterns like \"*.go\"","If generating JSON from YAML/templates, stringify keys explicitly","Validate with 'jq .' — it rejects unquoted keys at the exact line","Add a config linter step that rejects non-string map keys before load"],"tags":["config","json-parsing","rules"],"backgroundTag":"invalid-json-config","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}