alibaba/open-code-review · error

expected string key in path_rule_map, got %T

Error message

expected string key in path_rule_map, got %T

What it means

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.

Source

Thrown at internal/config/rules/system_rules.go:77

	// 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})
	}
	return nil
}

//go:embed system_rules.json rule_docs/*
var rulesFS embed.FS

// LoadDefault parses the embedded system_rules.json and resolves rule file references.
func LoadDefault() (*SystemRule, error) {
	data, err := rulesFS.ReadFile("system_rules.json")
	if err != nil {

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Quote every key in path_rule_map as a JSON string: "*.go" not *.go
  2. Validate with 'jq .' — it rejects unquoted keys and points at the line
  3. Regenerate the config from a schema/template that quotes keys
  4. If keys must be non-strings upstream, stringify them before writing the JSON

Example fix

// before
{"*.go": "golang.md", 42: "misc.md"}
// after
{"*.go": "golang.md", "42": "misc.md"}
Defensive patterns

Strategy: validation

Validate before calling

func keysAreStrings(data []byte) error {
    dec := json.NewDecoder(bytes.NewReader(data))
    if _, err := dec.Token(); err != nil { return err }
    for dec.More() {
        tok, err := dec.Token()
        if err != nil { return err }
        if _, ok := tok.(string); !ok {
            return fmt.Errorf("non-string key token %T", tok)
        }
        var v json.RawMessage
        if err := dec.Decode(&v); err != nil { return err }
    }
    return nil
}

Type guard

func allKeysQuoted(raw string) bool {
    // strip the braces; every key must start with '"'
    inner := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(raw), "{"), "}"))
    if inner == "" { return true }
    for _, part := range strings.Split(inner, ",") {
        if !strings.HasPrefix(strings.TrimSpace(part), "\"") { return false }
    }
    return true
}

Try / catch

if err := json.Unmarshal(data, &rule); err != nil {
    if strings.Contains(err.Error(), "expected string key in path_rule_map") {
        return fmt.Errorf("quote every glob key in path_rule_map: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: Hand-edited configs forgetting quotes around glob patterns; YAML-to-JSON converters emitting numeric keys; generator scripts interpolating keys without quoting.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/7fabd074fa0d85ba. Report an issue: GitHub.