Skip to content

RPC HttpRequest passes GET/HEAD bodies to WHATWG Request and fails before handler #458

Description

@borisgefterresimac

Version

  • @azure/functions: reproduced on 4.16.0, 4.16.1, and 4.16.2
  • Node.js: production Node 20; also reproduced locally on Node 24
  • Azure Functions Core Tools: 4.8.0
  • Hosting: Azure Static Web Apps managed Functions

Reproduction

const { HttpRequest } = require('@azure/functions');

new HttpRequest({
  url: 'https://example.test/api/probe',
  method: 'GET',
  body: { string: 'x' },
});

This throws before an application handler can run:

TypeError: Request with GET/HEAD method cannot have body.
    at new Request (node:internal/deps/undici/undici:10023:17)
    at new HttpRequest (@azure/functions/dist/azure-functions.js:2136:25)
    at fromRpcTypedData
    at InvocationModel.getArguments

The public SWA behavior was also deterministic before applying an application workaround:

curl -X GET --data x https://red-river-0f7efed00.7.azurestaticapps.net/api/health/bootstrap

A GET with a body returned a bare 500 and never reached the handler. The same request with no body or Content-Length: 0 reached the handler and returned its expected 401 JSON auth response.

Cause

In 4.16.x, the non-streaming RPC HttpRequest constructor passes the decoded RPC body to the global WHATWG Request for every method. The streaming createStreamRequest path already omits the body for GET and HEAD. The two paths therefore behave differently.

Organic body provenance is unknown because the available telemetry does not retain request headers/body length or client identity. Possible sources include malformed external traffic or an upstream host/proxy handoff; this report only claims the deterministic library failure once RPC data contains a GET/HEAD body.

Expected behavior

The RPC path should match the streaming path and omit body for GET and HEAD before constructing the WHATWG Request. A regression test should cover GET/HEAD bodies (including zero-length RPC bodies), mixed-case methods if accepted internally, and preservation of POST/PUT/PATCH bodies.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions