{"record":{"id":"92ea61dd9498b82b","repo":"geektutu/7days-golang","slug":"rpc-client-err-wrong-format-s-expect-protocol-92ea61","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/day6-load-balance/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/day6-load-balance/client.go#L295-L324","documentation":"Identical to error 80 but in day6-load-balance: XDial splits rpcAddr on '@' and requires exactly two parts; anything else is rejected with this message. The unified protocol@addr format lets one dial function dispatch to http or default (tcp) transports.","triggerScenarios":"XDial called with '10.0.0.1:9999' (no '@'), 'http@10.0.0.1:7001@x' (two '@'), or an empty string.","commonSituations":"Hardcoded addresses copied from Dial usage; service-registry entries lacking the protocol prefix; string formatting bugs injecting extra '@' characters.","solutions":["Format the address as protocol@addr with a single '@', e.g. 'http@10.0.0.1:7001'.","Prepend 'tcp@' (or the appropriate protocol) when the registry returns bare addresses.","Call Dial/DialHTTP directly if you already know the transport and don't need XDial parsing."],"exampleFix":"// before\nXDial(registryAddr) // e.g. \"http://localhost:9999/_geerpc_\"\n// after\nXDial(\"http@localhost: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) { /* normalize to protocol@addr before XDial */ }","typeGuard":null,"tryCatchPattern":"c, err := geerpc.XDial(rpcAddr)\nif err != nil {\n    if strings.Contains(err.Error(), \"wrong format\") {\n        return nil, fmt.Errorf(\"rpcAddr %q must be protocol@addr\", rpcAddr)\n    }\n    return nil, err\n}","preventionTips":["Normalize registry URLs (strip scheme://) into protocol@addr before storing.","Validate addresses when they enter your system, not at dial time.","Centralize dialing in one helper that owns the format check.","Test every address-producing code path (registry, env vars, flags)."],"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"}