grpc/grpc-go · error
rls: json marshal failed for child policy config
Error message
rls: json marshal failed for child policy config {%+v}: %v What it means
Emitted from parseChildPolicyConfigs (config.go:315) when json.Marshal of the augmented child-config map (original entries plus a dummy target field) fails. Because the map was just produced by json.Unmarshal of valid JSON, re-marshaling should not fail; this branch is defensive and effectively unreachable in normal operation.
Solutions
- Ensure the child policy config is plain valid JSON with no exotic RawMessage tricks.
- Avoid sharing/mutating the config bytes across goroutines while ParseConfig runs.
- If reproducible, minimize the child config to the smallest snippet that triggers it and file a bug; this path is not expected to fire in production.
Defensive patterns
Strategy: validation
Validate before calling
func validateChildConfigRoundTrip(raw json.RawMessage) error {
var m map[string]json.RawMessage
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
m["__target__"], _ = json.Marshal("placeholder")
if _, err := json.Marshal(m); err != nil {
return fmt.Errorf("child config does not round-trip: %w", err)
}
return nil
} Type guard
func childConfigRoundTrips(raw json.RawMessage) bool {
return validateChildConfigRoundTrip(raw) == nil
} Prevention
- Use plain valid JSON for child configs; avoid exotic RawMessage tricks.
- Do not mutate the parsed config concurrently with ParseConfig.
- Treat hitting this guard as a bug to report; it is not expected in production.
When it happens
Trigger: Only reachable if a json.RawMessage value inside the unmarshaled map is simultaneously valid for unmarshal but invalid for marshal, or via concurrent unsafe mutation during the brief window between unmarshal and marshal in parseChildPolicyConfigs.
Common situations: Essentially a defensive guard; if hit, suspect memory corruption, an unsafe.Pointer-based mutation, or a non-standard encoding/json replacement.
Related errors
- failed to marshal child policy config %+v
- failed to marshal child policy target
- rls: json unmarshal failed for child policy config
- rls: childPolicy config validation failed
- rls: childPolicy with config does not support config parsing
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/af2bc199d28fa57d.
Report an issue: GitHub.
Appendix: source
Thrown at balancer/rls/config.go:315
}
parser, ok := builder.(balancer.ConfigParser)
if !ok {
return "", nil, fmt.Errorf("rls: childPolicy %q with config %q does not support config parsing", name, string(rawCfg))
}
// To validate child policy configs we do the following:
// - unmarshal the raw JSON bytes of the child policy config into a map
// - add an entry with key set to `target_field_name` and a dummy value
// - marshal the map back to JSON and parse the config using the parser
// retrieved previously
var childConfig map[string]json.RawMessage
if err := json.Unmarshal(rawCfg, &childConfig); err != nil {
return "", nil, fmt.Errorf("rls: json unmarshal failed for child policy config %q: %v", string(rawCfg), err)
}
childConfig[targetFieldName], _ = json.Marshal(dummyChildPolicyTarget)
jsonCfg, err := json.Marshal(childConfig)
if err != nil {
return "", nil, fmt.Errorf("rls: json marshal failed for child policy config {%+v}: %v", childConfig, err)
}
if _, err := parser.ParseConfig(jsonCfg); err != nil {
return "", nil, fmt.Errorf("rls: childPolicy config validation failed: %v", err)
}
return name, childConfig, nil
}
return "", nil, fmt.Errorf("rls: invalid childPolicy config: no supported policies found in %+v", childPolicies)
}
func convertDuration(d *durationpb.Duration) (time.Duration, error) {
if d == nil {
return 0, nil
}
return d.AsDuration(), d.CheckValid()
}
View on GitHub (pinned to 0c51461d27)