{"record":{"id":"6e6e3c87d952279b","repo":"geektutu/7days-golang","slug":"rpc-client-err-wrong-format-s-expect-protocol","errorCode":null,"errorMessage":"rpc client err: wrong format '%s', expect protocol@addr","messagePattern":"rpc client err: wrong format '(.+?)', expect protocol@addr","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day5-http-debug/client.go","lineNumber":313,"sourceCode":"\t\terr = errors.New(\"unexpected HTTP response: \" + resp.Status)\n\t}\n\treturn nil, err\n}\n\n// DialHTTP connects to an HTTP RPC server at the specified network address\n// listening on the default HTTP RPC path.\nfunc DialHTTP(network, address string, opts ...*Option) (*Client, error) {\n\treturn dialTimeout(NewHTTPClient, network, address, opts...)\n}\n\n// XDial calls different functions to connect to a RPC server\n// according the first parameter rpcAddr.\n// rpcAddr is a general format (protocol@addr) to represent a rpc server\n// eg, http@10.0.0.1:7001, tcp@10.0.0.1:9999, unix@/tmp/geerpc.sock\nfunc XDial(rpcAddr string, opts ...*Option) (*Client, error) {\n\tparts := strings.Split(rpcAddr, \"@\")\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"rpc client err: wrong format '%s', expect protocol@addr\", rpcAddr)\n\t}\n\tprotocol, addr := parts[0], parts[1]\n\tswitch protocol {\n\tcase \"http\":\n\t\treturn DialHTTP(\"tcp\", addr, opts...)\n\tdefault:\n\t\t// tcp, unix or other transport protocol\n\t\treturn Dial(protocol, addr, opts...)\n\t}\n}\n","sourceCodeStart":295,"sourceCodeEnd":324,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day5-http-debug/client.go#L295-L324","documentation":"XDial parses a unified rpcAddr string of the form protocol@addr and returns an error when the string does not split into exactly two '@'-separated parts. The library uses this format to support multiple transports (http, tcp, unix) behind a single dial entry point. A malformed address cannot be routed to any transport, so dialing is refused immediately.","triggerScenarios":"Calling XDial with a rpcAddr that contains no '@' (e.g. '10.0.0.1:9999') or more than one '@' (e.g. 'http@10.0.0.1:7001@extra').","commonSituations":"Config files storing bare host:port addresses instead of protocol@addr; users forgetting the protocol prefix; template/env var interpolation inserting an extra '@' (e.g. credentials in a URL).","solutions":["Ensure rpcAddr contains exactly one '@' separating protocol from address, e.g. 'tcp@10.0.0.1:9999'.","If the address lacks a protocol prefix, prepend the desired one ('http@', 'tcp@', or 'unix@') before calling XDial.","For plain addresses, call Dial('tcp', addr) directly instead of XDial."],"exampleFix":"// before\nclient, err := geerpc.XDial(\"10.0.0.1:9999\")\n// after\nclient, err := geerpc.XDial(\"tcp@10.0.0.1:9999\")","handlingStrategy":"validation","validationCode":"func validRPCAddr(addr string) bool {\n    parts := strings.Split(addr, \"@\")\n    return len(parts) == 2 && parts[0] != \"\" && parts[1] != \"\"\n}\nif !validRPCAddr(rpcAddr) { /* fix or reject before calling XDial */ }","typeGuard":null,"tryCatchPattern":"c, err := geerpc.XDial(rpcAddr)\nif err != nil {\n    if strings.Contains(err.Error(), \"wrong format\") {\n        // fall back to a default protocol prefix\n        c, err = geerpc.XDial(\"tcp@\" + rpcAddr)\n    }\n    if err != nil { log.Fatal(err) }\n}","preventionTips":["Store addresses in config already as protocol@addr.","Validate the '@' format at config-load time.","Prefer Dial/DialHTTP when the protocol is static.","Add a unit test for each address template your app generates."],"tags":["rpc","address-format","validation"],"backgroundTag":"invalid-address-format","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}