{"record":{"id":"6c83f8a942fc5075","repo":"grpc/grpc-go","slug":"passthrough-received-empty-target-in-build","errorCode":null,"errorMessage":"passthrough: received empty target in Build()","messagePattern":"passthrough: received empty target in Build\\(\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/resolver/passthrough/passthrough.go","lineNumber":35,"sourceCode":" */\n\n// Package passthrough implements a pass-through resolver. It sends the target\n// name without scheme back to gRPC as resolved address.\npackage passthrough\n\nimport (\n\t\"errors\"\n\n\t\"google.golang.org/grpc/resolver\"\n)\n\nconst scheme = \"passthrough\"\n\ntype passthroughBuilder struct{}\n\nfunc (*passthroughBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {\n\tif target.Endpoint() == \"\" && opts.Dialer == nil {\n\t\treturn nil, errors.New(\"passthrough: received empty target in Build()\")\n\t}\n\tr := &passthroughResolver{\n\t\ttarget: target,\n\t\tcc:     cc,\n\t}\n\tr.start()\n\treturn r, nil\n}\n\nfunc (*passthroughBuilder) Scheme() string {\n\treturn scheme\n}\n\ntype passthroughResolver struct {\n\ttarget resolver.Target\n\tcc     resolver.ClientConn\n}\n","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/resolver/passthrough/passthrough.go#L17-L53","documentation":"Returned by passthroughBuilder.Build (internal/resolver/passthrough/passthrough.go:35) when target.Endpoint() is empty AND opts.Dialer is nil. The passthrough resolver hands the endpoint straight to gRPC as the address; with no endpoint and no custom dialer there is nothing to dial, so Build fails. Note the condition: a custom dialer makes an empty endpoint acceptable (the dialer decides where to connect).","triggerScenarios":"Dialing with the passthrough scheme (or default scheme) where the target string has no endpoint, e.g. grpc.Dial(\"passthrough:///\") or grpc.Dial(\"\") without a WithContextDialer option. The resolver Build() runs during Dial and returns this error.","commonSituations":"Empty target string passed to grpc.Dial; building a target programmatically and the host portion is empty; using the default resolver (which falls back to passthrough) with a malformed address; expecting an env var to fill the address but it is unset.","solutions":["Pass a non-empty target to grpc.Dial, e.g. grpc.Dial(\"passthrough:///backend.example.com:443\").","If you intentionally dial with an empty endpoint, supply a custom dialer via grpc.WithContextDialer (Build allows empty endpoint when opts.Dialer != nil).","Validate the address string is non-empty before Dialing."],"exampleFix":"// before\nconn, _ := grpc.Dial(\"passthrough:///\", ...) // err: received empty target\n\n// after\naddr := os.Getenv(\"BACKEND_ADDR\")\nif addr == \"\" { log.Fatal(\"BACKEND_ADDR not set\") }\nconn, err := grpc.Dial(\"passthrough:///\"+addr, ...)\n\n// alternate: custom dialer with empty endpoint\n// conn, _ := grpc.Dial(\"passthrough:///\", grpc.WithContextDialer(myDialer))","handlingStrategy":"validation","validationCode":"endpoint := strings.TrimSpace(rawTarget)\nif endpoint == \"\" && customDialer == nil {\n    return errors.New(\"dial target is empty; provide an address or a custom dialer\")\n}\ndialTarget := \"passthrough:///\" + endpoint","typeGuard":null,"tryCatchPattern":"conn, err := grpc.Dial(target, ...)\nif err != nil {\n    if strings.Contains(err.Error(), \"passthrough: received empty target\") {\n        log.Fatal(\"dial target empty; set BACKEND_ADDR or pass a dialer\")\n    }\n    log.Fatal(err)\n}","preventionTips":["Validate the dial address is non-empty before calling grpc.Dial.","If you must dial an empty target, supply grpc.WithContextDialer so Build accepts it."],"tags":["go","grpc","resolver","passthrough","naming","config-validation"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}