Skip to content

convertToQueryString drops query params with special chars (#, &, +) — re-serializes decoded values without encoding #1187

Description

@peters-lab

Summary

convertToQueryString in core/routing/util.ts rebuilds the request query string with raw template concatenation (${key}=${value}), but the request converters feed it already-decoded query values (via getQueryFromSearchParams). When a query value contains a character that is significant in a URL — most visibly #, but also &, +, = — the reconstructed req.url is corrupted.

For #, the decoded value becomes a URL fragment and everything after it is dropped, so the param is lost entirely.

Root cause

  • Converter decodes values: core/overrides/converters/edge.jsgetQueryFromSearchParams(new URL(event.url).searchParams) yields decoded values, e.g. q = "#sinners".
  • requestHandler rebuilds the URL from those decoded values:
    // core/requestHandler.ts (setInitialURL override)
    req.url = initialURL.pathname + convertToQueryString(routingResult.internalEvent.query);
  • convertToQueryString does not encode:
    queryStrings.push(`${key}=${value}`); // → "q=#sinners"
  • The route then does new URL(req.url)#sinners is treated as a fragment → searchParams.get("q") === "".

The function comment says "query should be properly encoded before using this function", but the converter hands it decoded values — an internal contract mismatch.

Reproduction

App with a route that reads new URL(request.url).searchParams.get("q"), request:

GET /api/search?q=%23sinners
  • Expected: q === "#sinners"
  • Actual: q === "" (route sees ?q=)

Also reproduces with q=rock%20%26%20roll → route sees q = "rock " (truncated at &).

Reproduces on the OpenNext Cloudflare adapter (@opennextjs/cloudflare) and is present in current main. Tested on @opennextjs/aws@4.0.2.

Suggested fix

Encode keys/values in convertToQueryString (or keep values encoded through the converter):

queryStrings.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);

Environment

  • @opennextjs/cloudflare 1.19.x, @opennextjs/aws 4.0.2
  • Next.js 15.5.x, Cloudflare Workers

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions