grpc/grpc-go · error
failed to marshal child policy target %q: %v
Error message
failed to marshal child policy target %q: %v
What it means
Emitted from rlsBalancer.buildAndPushChildPolicyConfigs when encoding/json cannot marshal the RLS-resolved backend target string (json.Marshal(target) at balancer.go:458). json.Marshal on a Go string only fails when the string contains invalid UTF-8 (e.g. lone surrogates or an unpaired continuation byte), so in practice this fires only for a corrupt target returned by the Route Lookup Server or set in the config's defaultTarget. On failure the childPolicyWrapper is put into lame-duck mode via cpw.lamify(err), so RPCs routed to that target fail fast until a new valid target arrives.
Source
Thrown at balancer/rls/balancer.go:459
// Default target has already been taken care of.
continue
}
if err := b.buildAndPushChildPolicyConfigs(cpw.target, newCfg, ccs); err != nil {
cpw.lamify(err)
}
}
}
// buildAndPushChildPolicyConfigs builds the final child policy configuration by
// adding the `targetField` to the base child policy configuration received in
// RLS LB policy configuration. The `targetField` is set to target and
// configuration is pushed to the child policy through the BalancerGroup.
//
// Caller must hold lb.stateMu.
func (b *rlsBalancer) buildAndPushChildPolicyConfigs(target string, newCfg *lbConfig, ccs *balancer.ClientConnState) error {
jsonTarget, err := json.Marshal(target)
if err != nil {
return fmt.Errorf("failed to marshal child policy target %q: %v", target, err)
}
config := newCfg.childPolicyConfig
targetField := newCfg.childPolicyTargetField
config[targetField] = jsonTarget
jsonCfg, err := json.Marshal(config)
if err != nil {
return fmt.Errorf("failed to marshal child policy config %+v: %v", config, err)
}
parser, _ := b.childPolicyBuilder.(balancer.ConfigParser)
parsedCfg, err := parser.ParseConfig(jsonCfg)
if err != nil {
return fmt.Errorf("childPolicy config parsing failed: %v", err)
}
state := balancer.ClientConnState{ResolverState: ccs.ResolverState, BalancerConfig: parsedCfg}
b.logger.Infof("Pushing new state to child policy %q: %+v", target, state)View on GitHub (pinned to 0c51461d27)
Solutions
- Inspect the RLS server response payload: dump the target field hex to confirm invalid UTF-8 and fix the server-side data source.
- If defaultTarget is the source, correct the value in the service config / xDS RLS config to a valid UTF-8 backend address such as 'dns:///backend.example:443'.
- Verify there is no proxy/middlebox corrupting the RLS gRPC response (check mTLS terminators, transcoding proxies).
- Add server-side input validation in the RLS service so targets are validated RFC 3986 host:port strings before being returned.
Example fix
// before: defaultTarget contains invalid bytes (e.g. lone surrogate) "defaultTarget": "backend\ud800example:443" // after: valid UTF-8 target URI "defaultTarget": "dns:///backend.example:443"
Defensive patterns
Strategy: validation
Validate before calling
// Validate an RLS-returned target before pushing it to a child policy.
func validTarget(s string) bool {
if !utf8.ValidString(s) {
return false
}
// Must round-trip through encoding/json for a string.
b, err := json.Marshal(s)
return err == nil && len(b) >= 2
} Type guard
func isValidRLSTarget(t string) bool {
return utf8.ValidString(t) && json.Valid([]byte(strconv.Quote(t)))
} Prevention
- Validate RLS server responses at the server side: target fields must be valid UTF-8 host[:port] strings.
- Keep defaultTarget in the service config to a stable, literal URI such as 'dns:///host:port'.
- In tests, construct targets via net.JoinHostPort rather than raw byte concatenation.
When it happens
Trigger: The RLS server returns a lookup response whose target field contains invalid UTF-8, or the service config's defaultTarget field contains invalid UTF-8 bytes. Also reachable if a hand-crafted RLS response in tests injects a malformed string. Triggered during UpdateClientConnState / config propagation when each child's target is marshaled before being injected into the child policy config.
Common situations: A misbehaving or compromised RLS server emitting garbage bytes in target fields; binary/null bytes accidentally embedded in defaultTarget in a hand-authored service config; corrupted xDS/RLS payload over the wire; test fixtures that build targets from raw byte slices.
Related errors
- failed to marshal child policy config %+v: %v
- rls: json marshal failed for child policy config {%+v}: %v
- rls: json unmarshal failed for child policy config %q: %v
- rls: json unmarshal failed for service config %+v: %v
- rls: childPolicyConfigTargetFieldName field is not set in se
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/4d0b0e23cdaf5b15.
Report an issue: GitHub.