grpc/grpc-go · error

invalid (non-empty) authority

Error message

invalid (non-empty) authority: %v

What it means

The unix and unix-abstract resolvers expect the dial target's URL to carry no authority (host) component — the socket path lives in the URL path or opaque part (e.g. "unix:///tmp/sock" or "unix:tmp/sock"). At unix.go:36-39, if target.URL.Host is non-empty the builder refuses to build. This prevents ambiguity between authority and socket path.

Solutions

  1. Use the empty-authority form: "unix:///absolute/path/to/socket".
  2. Or use the opaque form: "unix:relative/path".
  3. Remove any host/authority segment between 'unix://' and the path.

Example fix

// before:
//   conn, err := grpc.Dial("unix://localhost/tmp/x.sock", opts)
//   // error: invalid (non-empty) authority: localhost

// after:
//   conn, err := grpc.Dial("unix:///tmp/x.sock", opts)
Defensive patterns

Strategy: validation

Validate before calling

package main

import (
	"fmt"
	"net/url"
	"strings"
)

// validateUnixTarget ensures the authority is empty for unix/unix-abstract.
func validateUnixTarget(raw string) error {
	u, err := url.Parse(raw)
	if err != nil {
		return fmt.Errorf("unparseable unix target %q: %w", raw, err)
	}
	if u.Host != "" {
		return fmt.Errorf("unix target must have empty authority, got %q", u.Host)
	}
	if u.Path == "" && u.Opaque == "" {
		return fmt.Errorf("unix target has no socket path")
	}
	return nil
}

var _ = strings.TrimSpace

// func main() { _ = validateUnixTarget("unix:///tmp/x.sock") }

Try / catch

// grpc.Dial surfaces this synchronously from the unix resolver's Build.
//
//   conn, err := grpc.Dial(target, opts)
//   if err != nil && strings.Contains(err.Error(), "invalid (non-empty) authority") {
//       return fmt.Errorf("use unix:///path (empty authority), not unix://host/path")
//   }

Prevention

When it happens

Trigger: Triggered when the unix/unix-abstract resolver's Build receives a target whose URL.Host is set, e.g. "unix://localhost/tmp/sock" (authority 'localhost'), which is a common mis-formatting of unix targets.

Common situations: A developer writes the target as "unix://<host>/path" out of habit from http-style URLs, or a config template inserts an authority. The correct forms are "unix:///path/to/sock" (three slashes, empty authority) or "unix:path/to/sock".

Related errors


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

Appendix: 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 0c51461d27)