kataras/iris · error

client.Do: default request option[%d]: %w

Error message

client.Do: default request option[%d]: %w

What it means

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.

Source

Thrown at x/client/client.go:265

	if c.BaseURL != "" {
		urlpath = c.BaseURL + urlpath // note that we don't do any special checks here, the caller is responsible.
	}

	// Initialize the request.
	req, err := http.NewRequestWithContext(ctx, method, urlpath, body)
	if err != nil {
		return nil, err
	}

	// We separate the error for the default options for now.
	for i, opt := range c.PersistentRequestOptions {
		if opt == nil {
			continue
		}

		if err = opt(req); err != nil {
			return nil, fmt.Errorf("client.Do: default request option[%d]: %w", i, err)
		}
	}

	// Apply any custom request options (e.g. content type, accept headers, query...)
	for _, opt := range opts {
		if opt == nil {
			continue
		}

		if err = opt(req); err != nil {
			return nil, err
		}
	}

	if err = c.emitBeginRequest(ctx, req); err != nil {
		return nil, err
	}

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. 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.
  2. Validate the option's inputs (token, header value, URL) when constructing the Client rather than at request time, returning an error once at startup.
  3. If the option should be optional, make it skip gracefully (return nil) when its prerequisites are missing instead of erroring per request.
  4. Check recent changes to PersistentRequestOptions registration (env vars, secrets, config loading) that could make the option fail.
  5. Unwrap the error (errors.Unwrap / errors.As) to see the root cause returned by the failing option.

Example fix

// before: fails at request time when token is missing
client.PersistentRequestOptions = append(client.PersistentRequestOptions, func(r *http.Request) error {
    tok := os.Getenv("API_TOKEN")
    if tok == "" { return errors.New("empty token") }
    r.Header.Set("Authorization", "Bearer "+tok)
    return nil
})

// after: validate once at client construction
if os.Getenv("API_TOKEN") == "" { return nil, errors.New("API_TOKEN required") }
client.PersistentRequestOptions = append(client.PersistentRequestOptions, func(r *http.Request) error {
    r.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))
    return nil
})
Defensive patterns

Strategy: validation

Validate before calling

for i, opt := range client.PersistentRequestOptions {
    if opt == nil { continue }
    probe, _ := http.NewRequest(http.MethodGet, "https://example.invalid/", nil)
    if err := opt(probe); err != nil {
        return fmt.Errorf("persistent request option[%d] invalid: %w", i, err)
    }
}
// run once at client construction/startup

Try / catch

var optErr *RequestOptionError
if err := client.ReadJSON(ctx, &dest, method, path, nil); err != nil {
    if strings.Contains(err.Error(), "default request option[") && errors.As(err, &optErr) {
        // fix/rebuild client config, do not retry blindly
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/88bcd0e1a1ac537c. Report an issue: GitHub.