{"record":{"id":"3925b2a26960c9bf","repo":"geektutu/7days-golang","slug":"number-of-options-is-more-than-1-3925b2","errorCode":null,"errorMessage":"number of options is more than 1","messagePattern":"number of options is more than 1","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day6-load-balance/client.go","lineNumber":203,"sourceCode":"// and returns its error status.\nfunc (client *Client) Call(ctx context.Context, serviceMethod string, args, reply interface{}) error {\n\tcall := client.Go(serviceMethod, args, reply, make(chan *Call, 1))\n\tselect {\n\tcase <-ctx.Done():\n\t\tclient.removeCall(call.Seq)\n\t\treturn errors.New(\"rpc client: call failed: \" + ctx.Err().Error())\n\tcase call := <-call.Done:\n\t\treturn call.Error\n\t}\n}\n\nfunc parseOptions(opts ...*Option) (*Option, error) {\n\t// if opts is nil or pass nil as parameter\n\tif len(opts) == 0 || opts[0] == nil {\n\t\treturn DefaultOption, nil\n\t}\n\tif len(opts) != 1 {\n\t\treturn nil, errors.New(\"number of options is more than 1\")\n\t}\n\topt := opts[0]\n\topt.MagicNumber = DefaultOption.MagicNumber\n\tif opt.CodecType == \"\" {\n\t\topt.CodecType = DefaultOption.CodecType\n\t}\n\treturn opt, nil\n}\n\nfunc NewClient(conn net.Conn, opt *Option) (*Client, error) {\n\tf := codec.NewCodecFuncMap[opt.CodecType]\n\tif f == nil {\n\t\terr := fmt.Errorf(\"invalid codec type %s\", opt.CodecType)\n\t\tlog.Println(\"rpc client: codec error:\", err)\n\t\treturn nil, err\n\t}\n\t// send options with server\n\tif err := json.NewEncoder(conn).Encode(opt); err != nil {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day6-load-balance/client.go#L185-L221","documentation":"parseOptions() accepts variadic Option pointers and allows at most one; passing more than one returns \"number of options is more than 1\". It is called by dialTimeout and normalizes the provided option with defaults (MagicNumber, CodecType). This enforces a single-override API design.","triggerScenarios":"Calling Dial/DialTimeout/DialHTTP with two or more *Option arguments, e.g. dialTimeout(network, addr, opt1, opt2).","commonSituations":"Spreading a slice of options into the variadic parameter; merging config layers by passing each option; misunderstanding the variadic signature as accepting multiple configs.","solutions":["Pass exactly one *Option (or none to use DefaultOption)","Merge multiple configurations into a single Option struct before dialing","If spreading a slice, verify it has at most one element or merge it into one Option first"],"exampleFix":"// before\ndialTimeout(\"tcp\", addr, baseOpt, overrideOpt) // error\n\n// after\nopt := baseOpt // apply overrides onto one struct\nif overrideOpt != nil { opt = overrideOpt }\ndialTimeout(\"tcp\", addr, opt)","handlingStrategy":"validation","validationCode":"if len(opts) > 1 {\n    return errors.New(\"at most one *Option may be passed to dial\")\n}","typeGuard":null,"tryCatchPattern":"opt, err := parseOptions(myOpt)\nif err != nil {\n    return fmt.Errorf(\"dial config invalid: %w\", err)\n}","preventionTips":["Pass zero or one *Option; merge overrides into a single struct before dialing","Never spread an unbounded option slice into the variadic parameter","Write a small config-builder that produces exactly one Option from app config"],"tags":["rpc","configuration","api-misuse","go"],"backgroundTag":"too-many-arguments","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"}