{"record":{"id":"b0fb6155cedd890a","repo":"grpc/grpc-go","slug":"invalid-non-empty-authority-v","errorCode":null,"errorMessage":"invalid (non-empty) authority: %v","messagePattern":"invalid \\(non-empty\\) authority: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/resolver/unix/unix.go","lineNumber":38,"sourceCode":"package unix\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/grpc/internal/transport/networktype\"\n\t\"google.golang.org/grpc/resolver\"\n)\n\nconst unixScheme = \"unix\"\nconst unixAbstractScheme = \"unix-abstract\"\n\ntype builder struct {\n\tscheme string\n}\n\nfunc (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) {\n\tif target.URL.Host != \"\" {\n\t\treturn nil, fmt.Errorf(\"invalid (non-empty) authority: %v\", target.URL.Host)\n\t}\n\n\t// gRPC was parsing the dial target manually before PR #4817, and we\n\t// switched to using url.Parse() in that PR. To avoid breaking existing\n\t// resolver implementations we ended up stripping the leading \"/\" from the\n\t// endpoint. This obviously does not work for the \"unix\" scheme. Hence we\n\t// end up using the parsed URL instead.\n\tendpoint := target.URL.Path\n\tif endpoint == \"\" {\n\t\tendpoint = target.URL.Opaque\n\t}\n\taddr := resolver.Address{Addr: endpoint}\n\tif b.scheme == unixAbstractScheme {\n\t\t// We can not prepend \\0 as c++ gRPC does, as in Golang '@' is used to signify we do\n\t\t// not want trailing \\0 in address.\n\t\taddr.Addr = \"@\" + addr.Addr\n\t}\n\tcc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(addr, \"unix\")}})","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/resolver/unix/unix.go#L20-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Drop the authority: dial \"unix:///tmp/foo.sock\" (note the triple slash, leaving Host empty) or \"unix:/tmp/foo.sock\".","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), ...).","For abstract namespace sockets on Linux use the 'unix-abstract:' scheme with just the name, e.g. \"unix-abstract:myname\".","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."],"exampleFix":"// before\nconn, err := grpc.Dial(\"unix://localhost/run/docker.sock\", grpc.WithInsecure())\n\n// after\nconn, err := grpc.Dial(\"unix:///run/docker.sock\", grpc.WithInsecure())","handlingStrategy":"validation","validationCode":"func validUnixTarget(t string) error {\n    u, err := url.Parse(t)\n    if err != nil { return err }\n    if u.Scheme != \"unix\" && u.Scheme != \"unix-abstract\" { return fmt.Errorf(\"unexpected scheme %q\", u.Scheme) }\n    if u.Host != \"\" { return fmt.Errorf(\"unix target must have empty authority; got %q\", u.Host) }\n    return nil\n}\n\n// before dialing:\nif err := validUnixTarget(target); err != nil { return err }","typeGuard":"func isUnixTarget(t string) bool {\n    u, err := url.Parse(t)\n    return err == nil && (u.Scheme == \"unix\" || u.Scheme == \"unix-abstract\") && u.Host == \"\"\n}","tryCatchPattern":null,"preventionTips":["Always build unix dial targets with a helper that guarantees triple-slash form for the unix scheme.","Never interpolate a hostname into a unix:// URL; the unix resolver overrides authority to localhost anyway.","Lint dial target strings in CI to reject unix://<non-empty-host>."],"tags":["grpc","unix-socket","dial-target","resolver","configuration"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}