{"record":{"id":"8814e66c484bac82","repo":"grpc/grpc-go","slug":"dns-resolver-missing-address","errorCode":null,"errorMessage":"dns resolver: missing address","messagePattern":"dns resolver: missing address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/resolver/dns/internal/internal.go","lineNumber":41,"sourceCode":"\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"time\"\n)\n\n// NetResolver groups the methods on net.Resolver that are used by the DNS\n// resolver implementation. This allows the default net.Resolver instance to be\n// overridden from tests.\ntype NetResolver interface {\n\tLookupHost(ctx context.Context, host string) (addrs []string, err error)\n\tLookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)\n\tLookupTXT(ctx context.Context, name string) (txts []string, err error)\n}\n\nvar (\n\t// ErrMissingAddr is the error returned when building a DNS resolver when\n\t// the provided target name is empty.\n\tErrMissingAddr = errors.New(\"dns resolver: missing address\")\n\n\t// ErrEndsWithColon is the error returned when building a DNS resolver when\n\t// the provided target name ends with a colon that is supposed to be the\n\t// separator between host and port.  E.g. \"::\" is a valid address as it is\n\t// an IPv6 address (host only) and \"[::]:\" is invalid as it ends with a\n\t// colon as the host and port separator\n\tErrEndsWithColon = errors.New(\"dns resolver: missing port after port-separator colon\")\n)\n\n// The following vars are overridden from tests.\nvar (\n\t// TimeAfterFunc is used by the DNS resolver to wait for the given duration\n\t// to elapse. In non-test code, this is implemented by time.After. In test\n\t// code, this can be used to control the amount of time the resolver is\n\t// blocked waiting for the duration to elapse.\n\tTimeAfterFunc func(time.Duration) <-chan time.Time\n\n\t// TimeNowFunc is used by the DNS resolver to get the current time.","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/resolver/dns/internal/internal.go#L23-L59","documentation":"ErrMissingAddr (internal/resolver/dns/internal/internal.go:41) is the sentinel returned by the dns resolver builder when the target name passed in is empty. The dns resolver needs a host name to resolve; with an empty endpoint there is nothing to look up, so the resolver build fails immediately. Exported as a package var so callers can errors.Is-match it.","triggerScenarios":"Dialing with a dns:// target whose authority/endpoint is empty, e.g. grpc.Dial(\"dns:///\") or a programmatically-built target where Endpoint() returns \"\". The resolver Build() detects the empty endpoint and returns ErrMissingAddr, causing Dial to fail.","commonSituations":"Building a target string via fmt.Sprintf with an empty host var; dropping the host part while keeping the dns:// scheme; env var holding the backend host being unset so the dial target becomes dns:///:443; mis-parsed service discovery URL.","solutions":["Provide a non-empty host in the dns:// target, e.g. grpc.Dial(\"dns:///service.example.com:443\", ...).","Validate the resolved host string is non-empty before constructing the target.","Check for this specific error with errors.Is(err, internal.ErrMissingAddr) (or the resolver's typed error) to give a clearer startup message."],"exampleFix":"// before\nhost := os.Getenv(\"BACKEND_HOST\") // \"\"\nconn, _ := grpc.Dial(fmt.Sprintf(\"dns:///%s:443\", host), ...) // err: missing address\n\n// after\nhost := os.Getenv(\"BACKEND_HOST\")\nif host == \"\" { log.Fatal(\"BACKEND_HOST not set\") }\nconn, _ := grpc.Dial(fmt.Sprintf(\"dns:///%s:443\", host), ...)","handlingStrategy":"validation","validationCode":"host := strings.TrimSpace(targetHost)\nif host == \"\" {\n    return errors.New(\"dns target host is empty\")\n}\ndialTarget := fmt.Sprintf(\"dns:///%s\", host)","typeGuard":null,"tryCatchPattern":"conn, err := grpc.Dial(target, ...)\nif err != nil {\n    if errors.Is(err, internal.ErrMissingAddr) {\n        log.Fatal(\"dial target is empty; set the backend host\")\n    }\n    log.Fatal(err)\n}","preventionTips":["Validate the resolved host is non-empty before building the dns:// target.","Guard env-var-backed hosts with a non-empty check at startup."],"tags":["go","grpc","resolver","dns","naming","config-validation"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}