{"record":{"id":"88bcd0e1a1ac537c","repo":"kataras/iris","slug":"client-do-default-request-option-d-w","errorCode":null,"errorMessage":"client.Do: default request option[%d]: %w","messagePattern":"client\\.Do: default request option\\[(.+?)\\]: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/client/client.go","lineNumber":265,"sourceCode":"\n\tif c.BaseURL != \"\" {\n\t\turlpath = c.BaseURL + urlpath // note that we don't do any special checks here, the caller is responsible.\n\t}\n\n\t// Initialize the request.\n\treq, err := http.NewRequestWithContext(ctx, method, urlpath, body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// We separate the error for the default options for now.\n\tfor i, opt := range c.PersistentRequestOptions {\n\t\tif opt == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = opt(req); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"client.Do: default request option[%d]: %w\", i, err)\n\t\t}\n\t}\n\n\t// Apply any custom request options (e.g. content type, accept headers, query...)\n\tfor _, opt := range opts {\n\t\tif opt == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = opt(req); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err = c.emitBeginRequest(ctx, req); err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/x/client/client.go#L247-L283","documentation":"Client.Do wraps any error returned by one of the client's PersistentRequestOptions (default request option functions) with this message, including the option's index in the slice and the original error via %w. These options are applied to every outgoing request before the per-call custom options, so if one fails the request is never sent. It is a configuration-time bug in a registered default option, not a network or server problem.","triggerScenarios":"Any call to Client.Do, JSON, Form, ReadJSON, ReadPlain or WriteTo when an entry in c.PersistentRequestOptions returns a non-nil error while mutating the http.Request (e.g. a persistent auth-header option that fails to resolve a token, a base-path rewriter hitting an invalid URL, or a malformed persistent header value). The index in the message identifies which registered option failed.","commonSituations":"Registering PersistentRequestOptions on the Client (often at app init) with an option that depends on external state — an empty/expired API token, a context value that is absent when Do runs, a URL path that breaks after BaseURL concatenation, or a factory function that built an invalid option. Frequently surfaces after config or env changes (missing env var for a token provider).","solutions":["Read the [%d] index in the message and inspect the corresponding function in c.PersistentRequestOptions; fix or guard the code inside that option so it returns nil on the happy path.","Validate the option's inputs (token, header value, URL) when constructing the Client rather than at request time, returning an error once at startup.","If the option should be optional, make it skip gracefully (return nil) when its prerequisites are missing instead of erroring per request.","Check recent changes to PersistentRequestOptions registration (env vars, secrets, config loading) that could make the option fail.","Unwrap the error (errors.Unwrap / errors.As) to see the root cause returned by the failing option."],"exampleFix":"// before: fails at request time when token is missing\nclient.PersistentRequestOptions = append(client.PersistentRequestOptions, func(r *http.Request) error {\n    tok := os.Getenv(\"API_TOKEN\")\n    if tok == \"\" { return errors.New(\"empty token\") }\n    r.Header.Set(\"Authorization\", \"Bearer \"+tok)\n    return nil\n})\n\n// after: validate once at client construction\nif os.Getenv(\"API_TOKEN\") == \"\" { return nil, errors.New(\"API_TOKEN required\") }\nclient.PersistentRequestOptions = append(client.PersistentRequestOptions, func(r *http.Request) error {\n    r.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"API_TOKEN\"))\n    return nil\n})","handlingStrategy":"validation","validationCode":"for i, opt := range client.PersistentRequestOptions {\n    if opt == nil { continue }\n    probe, _ := http.NewRequest(http.MethodGet, \"https://example.invalid/\", nil)\n    if err := opt(probe); err != nil {\n        return fmt.Errorf(\"persistent request option[%d] invalid: %w\", i, err)\n    }\n}\n// run once at client construction/startup","typeGuard":null,"tryCatchPattern":"var optErr *RequestOptionError\nif err := client.ReadJSON(ctx, &dest, method, path, nil); err != nil {\n    if strings.Contains(err.Error(), \"default request option[\") && errors.As(err, &optErr) {\n        // fix/rebuild client config, do not retry blindly\n    }\n}","preventionTips":["Validate all inputs a persistent option needs (tokens, headers, base URL) once at client construction, not per request.","Keep PersistentRequestOptions minimal and side-effect free; prefer pure header setters.","Never register an option factory that can return an error-producing option without testing it at startup.","Log the option index from the error message to pinpoint the failing registration quickly."],"tags":["go","http-client","request-options","configuration"],"backgroundTag":"request-option-configuration-error","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}