grpc/grpc-go · error

invalid (non-empty) authority: %v

Error message

invalid (non-empty) authority: %v

What it means

Thrown by the gRPC unix socket resolver's Build method when the dial target URL contains a non-empty host (authority) component. The 'unix' and 'unix-abstract' schemes require the socket path to live entirely in the URL path/opaque portion, so any authority (e.g. a hostname between 'unix://' and the path) is rejected. It is a hard failure: the resolver returns the error and no connection is attempted.

Source

Thrown at internal/resolver/unix/unix.go:38

package unix

import (
	"fmt"

	"google.golang.org/grpc/internal/transport/networktype"
	"google.golang.org/grpc/resolver"
)

const unixScheme = "unix"
const unixAbstractScheme = "unix-abstract"

type builder struct {
	scheme string
}

func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) {
	if target.URL.Host != "" {
		return nil, fmt.Errorf("invalid (non-empty) authority: %v", target.URL.Host)
	}

	// gRPC was parsing the dial target manually before PR #4817, and we
	// switched to using url.Parse() in that PR. To avoid breaking existing
	// resolver implementations we ended up stripping the leading "/" from the
	// endpoint. This obviously does not work for the "unix" scheme. Hence we
	// end up using the parsed URL instead.
	endpoint := target.URL.Path
	if endpoint == "" {
		endpoint = target.URL.Opaque
	}
	addr := resolver.Address{Addr: endpoint}
	if b.scheme == unixAbstractScheme {
		// We can not prepend \0 as c++ gRPC does, as in Golang '@' is used to signify we do
		// not want trailing \0 in address.
		addr.Addr = "@" + addr.Addr
	}
	cc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(addr, "unix")}})

View on GitHub (pinned to 03255a9237)

Solutions

  1. Drop the authority: dial "unix:///tmp/foo.sock" (note the triple slash, leaving Host empty) or "unix:/tmp/foo.sock".
  2. If building the target dynamically, prepend only when the path lacks a scheme and never interpolate a hostname: grpc.Dial(fmt.Sprintf("unix:%s", sockPath), ...).
  3. For abstract namespace sockets on Linux use the 'unix-abstract:' scheme with just the name, e.g. "unix-abstract:myname".
  4. If you genuinely need to override authority, note OverrideAuthority forces 'localhost' anyway, so there is no supported way to keep a custom authority with the unix scheme.

Example fix

// before
conn, err := grpc.Dial("unix://localhost/run/docker.sock", grpc.WithInsecure())

// after
conn, err := grpc.Dial("unix:///run/docker.sock", grpc.WithInsecure())
Defensive patterns

Strategy: validation

Validate before calling

func validUnixTarget(t string) error {
    u, err := url.Parse(t)
    if err != nil { return err }
    if u.Scheme != "unix" && u.Scheme != "unix-abstract" { return fmt.Errorf("unexpected scheme %q", u.Scheme) }
    if u.Host != "" { return fmt.Errorf("unix target must have empty authority; got %q", u.Host) }
    return nil
}

// before dialing:
if err := validUnixTarget(target); err != nil { return err }

Type guard

func isUnixTarget(t string) bool {
    u, err := url.Parse(t)
    return err == nil && (u.Scheme == "unix" || u.Scheme == "unix-abstract") && u.Host == ""
}

Prevention

When it happens

Trigger: Dialing a target like "unix://localhost/tmp/foo.sock" or "unix://somehost/run/docker.sock" — anything where the URL parses a Host field. The check is the single guard `if target.URL.Host != ""` in unix.go:37, so even an authority that happens to be a valid hostname trips it.

Common situations: Developers copy a unix socket path from a Docker/containerd config that already embeds a host, or assemble the target via fmt.Sprintf("unix://%s", path) which yields three slashes only when path starts with '/'. Confusion between the gRPC-native 'unix:' scheme and a URL that looks RFC-conformant.

Related errors


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