grpc/grpc-go · error

config parser for Outlier Detection returned config with une

Error message

config parser for Outlier Detection returned config with unexpected type %T: %v

What it means

Returned by updateOutlierDetection (line 364) when the config returned by odParser.ParseConfig is not of type *outlierdetection.LBConfig (type assertion at line 360 fails). The %T shows the actual type and %v shows the value. The comment (lines 362-363) says this should never happen because the parser is obtained from the outlier detection builder at build time.

Source

Thrown at internal/xds/balancer/cdsbalancer/cdsbalancer.go:364

	}

	for _, p := range b.priorities {
		// Update Outlier Detection Config.
		odJSON := p.clusterConfig.Cluster.OutlierDetection
		if odJSON == nil {
			odJSON = json.RawMessage(`{}`)
		}

		lbCfg, err := odParser.ParseConfig(odJSON)
		if err != nil {
			return fmt.Errorf("error parsing Outlier Detection config %v: %v", odJSON, err)
		}

		odCfg, ok := lbCfg.(*outlierdetection.LBConfig)
		if !ok {
			// Shouldn't happen, Parser built at build time with Outlier
			// Detection builder pulled from gRPC LB Registry.
			return fmt.Errorf("config parser for Outlier Detection returned config with unexpected type %T: %v", lbCfg, lbCfg)
		}
		p.outlierDetection = *odCfg
	}
	return nil
}

// ResolverError handles errors reported by the xdsResolver.
func (b *cdsBalancer) ResolverError(err error) {
	// Missing Listener or RouteConfiguration on the management server
	// results in a 'resource not found' error from the xDS resolver. In
	// these cases, we should report transient failure.
	if xdsresource.ErrType(err) == xdsresource.ErrorTypeResourceNotFound {
		b.closeChildPolicyAndReportTF(err)
		return
	}
	var root string
	if b.lbCfg != nil {
		root = b.lbCfg.ClusterName

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Verify all grpc-go internal packages resolve to the same module version: 'go list -m -json google.golang.org/grpc'.
  2. Check for module shadowing or replace directives in go.mod that might pull a different outlierdetection package.
  3. Report as a bug to grpc-go if versions are consistent.
  4. Clean module cache and re-download: 'go clean -modcache && go mod download'.
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate that the OD parser returns the expected type (debug check)
func validateODParserType() error {
    b := balancer.Get(outlierdetection.Name)
    if b == nil {
        return fmt.Errorf("OD not registered")
    }
    parser, ok := b.(balancer.ConfigParser)
    if !ok {
        return fmt.Errorf("OD lacks parser")
    }
    cfg, err := parser.ParseConfig(json.RawMessage(`{}`))
    if err != nil {
        return fmt.Errorf("OD parse failed: %w", err)
    }
    if _, ok := cfg.(*outlierdetection.LBConfig); !ok {
        return fmt.Errorf("OD parser returned wrong type %T", cfg)
    }
    return nil
}

Type guard

func isODConfig(cfg serviceconfig.LoadBalancingConfig) bool {
    _, ok := cfg.(*outlierdetection.LBConfig)
    return ok
}

Prevention

When it happens

Trigger: The outlier detection builder's ParseConfig returns a config object whose concrete type is not *outlierdetection.LBConfig. This is an internal invariant violation — the builder and the expected return type are from the same package.

Common situations: Version skew or package shadowing where a different outlierdetection package is used for the builder vs. the type assertion. A forked outlier detection package that changed its config type. Extremely unlikely in stock grpc-go.

Related errors


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