Repository navigation
Conversation
RequestParser::bodyParams() accepted any associative array as a single
operation. A JSON object such as {"query":"...","0":"..."} decodes to a
PHP array with the integer key 0, which Arr::isAssoc() still reports as
associative, but which GraphQL\Server\Helper::parseRequestParams() treats
as a batch. webonyx then calls OperationParams::create() with the string
entries and the request ends in an uncaught TypeError (HTTP 500) instead
of a BadRequestGraphQLException (HTTP 400).
Use the same rule as webonyx to tell a batch from a single operation: a
body with the key 0 is a batch, and every entry of a batch must be an
object.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
A key 0 with a null value still bypasses the intended rejection path.
1 open finding
What changed in this PR
Ensures malformed GraphQL JSON bodies with numeric key 0 return HTTP 400 instead of causing an uncaught TypeError.
Changes:
- Aligns request validation with webonyx batch detection.
- Adds regression tests for malformed batch-like bodies.
- Documents the fix.
| File | Description |
|---|---|
src/RequestParser.php |
Validates bodies detected as batches. |
tests/Unit/RequestParserTest.php |
Adds malformed-body regression tests. |
CHANGELOG.md |
Records the corrected behavior. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
isset() is false for a null value, so [null] skipped the batch entry check.
inlineFiles() skipped the batch shape check, so multipart operations
such as {"query":"…","0":"x"} still caused a TypeError in webonyx.
Member
|
🤖 Thanks @pawell67, I pushed three commits on top of yours.
|
spawnia
approved these changes
Oct 12, 2026
spawnia
added a commit
to webonyx/graphql-php
that referenced
this pull request
Oct 12, 2026
Malformed batch bodies such as `["x"]` caused an uncaught `TypeError`
instead of a `RequestError`.
`Helper::parseRequestParams()` now rejects scalar batch entries.
<details>
<summary>An object with a non-null key `0` still counts as a batch, so
the message names the offending key</summary>
`{"query":"{ a }","0":"x"}` fails with `Expected batch entry query to be
an object, got: "{ a }"`.
Batch detection stays `isset($bodyParams[0])`, so `{"0":null,"query":"{
a }"}` is still a single operation.
No other server checked has a dedicated message for this case: JS
servers detect batches with `Array.isArray`, and
laragraph/utils#27 also uses a generic message.
</details>
<details>
<summary>The fix targets master only, not 14.x</summary>
14.x has the same bug, but its last release was
https://github.com/webonyx/graphql-php/releases/tag/v14.11.10 in 2023.
</details>
🤖 Generated with Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Problem
RequestParser::bodyParams()accepts any associative array as a single operation. A JSON object that also carries the key"0", e.g.{"query":"{ foo }","0":"not an operation"}decodes to a PHP array with the integer key
0.Arr::isAssoc()still reports it as associative, so the parser returns it as a single operation, butGraphQL\Server\Helper::parseRequestParams()usesisset($bodyParams[0])to detect a batch and then callsOperationParams::create()with each entry. The string entries make that an uncaughtTypeError:That surfaces as an HTTP 500 and an unhandled exception in error tracking, instead of the
BadRequestGraphQLException(HTTP 400) the parser throws for every other malformed body. We hit this in production from a scanner sending a multipart-upload-shaped payload (operations,map,"0") asapplication/json.Fix
Use the same rule as webonyx to tell a batch from a single operation: a body with the key
0is a batch, and every entry of a batch must be an object. Anything else falls through to the existingBadRequestGraphQLException.Behaviour for valid bodies is unchanged: a JSON object without the key
0is still a single operation, a list of objects is still a batch.Tests
testObjectWithNumericKeyIsNotABatchreproduces theTypeErroron master and passes with the fix.testBatchWithNonObjectEntrypins the existing rejection of a list containing a non-object entry.🤖 Generated with Claude Code