Skip to content

@hey-api/client-next: buildUrl called before request interceptors, so interceptor mutations to baseUrl/url/path/query are ignored by fetch() #3803

@jnsdls

Description

@jnsdls

Bug report

Package: @hey-api/client-next

Description

In the client generated by @hey-api/client-next, buildUrl(resolvedOpts) is called before the interceptors.request.fns loop. As a result, any request interceptor that mutates opts.baseUrl, opts.url, opts.path, or opts.query is silently ignored when constructing the URL passed to fetch().

The SSE path in the same generated file handles this correctly — it applies request interceptors before building the request URL — creating an asymmetry between the HTTP and SSE code paths.

Generated code (simplified)

// beforeRequest resolves url HERE — before interceptors run
const { opts, url } = await beforeRequest(options);

for (const fn of interceptors.request.fns) {
  if (fn) {
    await fn(opts); // mutations to opts.baseUrl / opts.url / opts.path / opts.query are ignored
  }
}

// url is stale — it was built from pre-interceptor opts
let response = await _fetch(url, requestInit);

Expected behaviour

url should be (re)computed from opts after all request interceptors have finished running, immediately before _fetch(url, requestInit). The order should be:

  1. beforeRequest (merge configs, set auth params, serialize body)
  2. Run interceptors.request.fns loop
  3. Build url from the (potentially mutated) opts
  4. Create requestInit
  5. Call _fetch(url, requestInit)

This matches the pattern already used in the SSE path in the same file.

Related

There's a similar (minor) issue in the same generated client: the error interceptor loop passes the original error into every interceptor instead of threading finalError through, so later interceptors never see transformations from earlier ones. Happy to split that out into its own issue if preferred.

Backlinks

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug 🔥Broken or incorrect behavior.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions