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

  1. Inspect the RLS server response payload: dump the target field hex to confirm invalid UTF-8 and fix the server-side data source.
  2. 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'.
  3. Verify there is no proxy/middlebox corrupting the RLS gRPC response (check mTLS terminators, transcoding proxies).
  4. 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

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


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/4d0b0e23cdaf5b15. Report an issue: GitHub.