grpc/grpc-go · error
rls: json marshal failed for child policy config {%+v}: %v
Error message
rls: json marshal failed for child policy config {%+v}: %v What it means
After injecting the dummy target field, RLS marshals the map[string]json.RawMessage back to JSON to hand to the child policy's ParseConfig. Because every value is already valid json.RawMessage and the key is a string, json.Marshal essentially cannot fail; this branch is a defensive guard. Hitting it indicates memory/type corruption or a custom RawMessage containing invalid bytes.
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 03255a9237)
Solutions
- Treat this as an internal bug: capture the exact config and gRPC-Go version and file an issue.
- Re-resolve/redeploy the service config fresh to rule out transient memory corruption.
- If running a fork, diff against upstream config.go around line 312-316.
Defensive patterns
Strategy: try-catch
Try / catch
if _, err := rlsBB{}.ParseConfig(rawCfg); err != nil {
if strings.Contains(err.Error(), "json marshal failed for child policy config") {
// defensively unreachable; log and fall back to a known-good config
logger.Errorw("internal RLS marshal failure", "err", err)
rawCfg = knownGoodConfig
} else {
return err
}
} Prevention
- Treat this error as an internal bug; report it with the config and gRPC version.
- Keep a known-good fallback service config to swap in if parse fails unexpectedly.
- Do not fork json.RawMessage handling in config.go.
When it happens
Trigger: Effectively unreachable in normal operation. Theoretically: a json.RawMessage value in the map that is not valid JSON and confuses the encoder, or an internal panic recovered into an error path.
Common situations: Near-impossible via config alone; would only appear with a corrupted in-memory config, a fork that mutated RawMessage fields, or a Go runtime/encoding bug.
Related errors
- rls: bad control channel service config %q: %v
- rls: stale_age is set, but max_age is not in route lookup co
- rls: cache_size_bytes must be set to a non-zero value: %+v
- rls: invalid childPolicy: entry %v does not contain exactly
- rls: childPolicy %q with config %q does not support config p
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/af2bc199d28fa57d.
Report an issue: GitHub.