grpc/grpc-go · error

could not get resolver for default scheme: %q

Error message

could not get resolver for default scheme: %q

What it means

In initParsedTargetAndResolverBuilder (clientconn.go:1852-1854), when the dial target had no scheme or an unregistered scheme, gRPC falls back to the default scheme and re-parses. If getResolver() still returns nil for that fallback scheme, the channel cannot proceed. The %q is the fallback scheme string that has no registered builder.

Source

Thrown at clientconn.go:1854

	// We are here because the user's dial target did not contain a scheme or
	// specified an unregistered scheme. We should fallback to the default
	// scheme, except when a custom dialer is specified in which case, we should
	// always use passthrough scheme. For either case, we need to respect any overridden
	// global defaults set by the user.
	defScheme := cc.dopts.defaultScheme
	if internal.UserSetDefaultScheme {
		defScheme = resolver.GetDefaultScheme()
	}

	canonicalTarget := defScheme + ":///" + cc.target

	parsedTarget, err = parseTarget(canonicalTarget)
	if err != nil {
		return err
	}
	rb = cc.getResolver(parsedTarget.URL.Scheme)
	if rb == nil {
		return fmt.Errorf("could not get resolver for default scheme: %q", parsedTarget.URL.Scheme)
	}
	cc.parsedTarget = parsedTarget
	cc.resolverBuilder = rb
	return nil
}

// parseTarget uses RFC 3986 semantics to parse the given target into a
// resolver.Target struct containing url. Query params are stripped from the
// endpoint.
func parseTarget(target string) (resolver.Target, error) {
	u, err := url.Parse(target)
	if err != nil {
		return resolver.Target{}, err
	}

	return resolver.Target{URL: *u}, nil
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Register a resolver builder for the scheme shown in the error (resolver.Register), or import the package that registers it.
  2. Prefix the target with a registered scheme such as dns:/// or passthrough:///.
  3. If you set a custom default scheme, ensure its builder is registered before Dial.

Example fix

// before
conn, err := grpc.NewClient("myservice:443")
// after
import _ "google.golang.org/grpc/internal/resolver/dns"
conn, err := grpc.NewClient("dns:///myservice:443")
Defensive patterns

Strategy: validation

Validate before calling

// Confirm a builder is registered for the effective scheme.
func checkScheme(scheme string) error {
    for _, s := range resolver.GetSchemes() { if s == scheme { return nil } }
    return fmt.Errorf("unregistered scheme: %q", scheme)
}

Prevention

When it happens

Trigger: Dialing with a bare target (no scheme) when the default scheme's resolver isn't registered, or explicitly using a scheme with no builder. Common after switching default scheme via UserSetDefaultScheme to something unregistered.

Common situations: Forgetting to register a custom resolver; setting a custom default scheme that has no builder; running a minimal binary that didn't import the dns resolver.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/72c91b26ace740bf. Report an issue: GitHub.