{"record":{"id":"1e60d8d2c2af1434","repo":"grpc/grpc-go","slug":"missing-address","errorCode":null,"errorMessage":"missing address","messagePattern":"missing address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/resolver/delegatingresolver/delegatingresolver.go","lineNumber":231,"sourceCode":"\t}\n\treturn false\n}\n\n// parseTarget takes a target string and ensures it is a valid \"host:port\" target.\n//\n// It does the following:\n//  1. If the target already has a port (e.g., \"host:port\", \"[ipv6]:port\"),\n//     it is returned as is.\n//  2. If the host part is empty (e.g., \":80\"), it defaults to \"localhost\",\n//     returning \"localhost:80\".\n//  3. If the target is missing a port (e.g., \"host\", \"ipv6\"), the defaultPort\n//     is added.\n//\n// An error is returned for empty targets or targets with a trailing colon\n// but no port (e.g., \"host:\").\nfunc parseTarget(target string) (string, error) {\n\tif target == \"\" {\n\t\treturn \"\", fmt.Errorf(\"missing address\")\n\t}\n\n\thost, port, err := net.SplitHostPort(target)\n\tif err != nil {\n\t\t// If SplitHostPort fails, it's likely because the port is missing.\n\t\t// We append the default port and return the result.\n\t\treturn net.JoinHostPort(target, defaultPort), nil\n\t}\n\n\t// If SplitHostPort succeeds, we check for edge cases.\n\tif port == \"\" {\n\t\t// A success with an empty port means the target had a trailing colon,\n\t\t// e.g., \"host:\", which is an error.\n\t\treturn \"\", fmt.Errorf(\"missing port after port-separator colon\")\n\t}\n\tif host == \"\" {\n\t\t// A success with an empty host means the target was like \":80\".\n\t\t// We default the host to \"localhost\".","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/resolver/delegatingresolver/delegatingresolver.go#L213-L249","documentation":"Returned by parseTarget (in the delegating resolver) when the target string is the empty string. This is the inner cause surfaced for dns targets with no host. It indicates the endpoint portion of the target URI was empty, so there is nothing to resolve.","triggerScenarios":"Dialing with an empty or whitespace target such as \"\", \"dns:///\", or a target built from an unset config value. parseTarget is also used internally by the dns resolver for its authority.","commonSituations":"Service discovery config that returns an empty address; dial target assembled from an unset environment variable; blank value passed through a flag default.","solutions":["Provide a non-empty host/port in the dial target.","Validate that the address is non-empty at the config boundary before dialing.","Fail fast at startup if the resolved target string is empty rather than dialing."],"exampleFix":"// before\ntarget := os.Getenv(\"SVC_ADDR\") // unset -> \"\"\nconn, _ := grpc.Dial(target, ...)\n// after\ntarget := os.Getenv(\"SVC_ADDR\")\nif target == \"\" { log.Fatal(\"SVC_ADDR required\") }\nconn, _ := grpc.Dial(target, ...)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(target) == \"\" {\n    return errors.New(\"dial target is empty\")\n}","typeGuard":null,"tryCatchPattern":"if target == \"\" {\n    return errors.New(\"cannot dial empty target\")\n}\nconn, err := grpc.Dial(target, ...)","preventionTips":["Validate non-empty target at the configuration boundary.","Refuse to start if service discovery returns an empty address.","Add a startup assertion for required address env vars."],"tags":["grpc","resolver","delegating-resolver","target-uri","validation"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}