pypi graphql-core 3.2.14
v3.2.14

one hour ago

Patch-release GraphQL-core v3.2.14, based on GraphQL.js v16.15.0.

This patch-release supports Python 3.7 to 3.15.

This release contains security fixes. It fixes four denial-of-service vulnerabilities in the validator and the parser, so upgrading is recommended for all users of GraphQL-core 3.2. It also includes behavior changes, new features and bug fixes, see below. The security fixes are also available for GraphQL-core 3.3 in version 3.3.2.

Security fixes:

  • MaxIntrospectionDepthRule walked fragments repeatedly, so validating a small document with the default rules could take exponential time. Fragments already checked at the same or a greater depth are now skipped. The rule also no longer raises RecursionError for long fragment chains under an introspection field.
  • Fragments shared by many operations were walked again for every operation, so validation with the default rules took quadratic time. Validation now also stops with "Validation aborted." once the work on shared fragments exceeds 50,000 units (module attribute graphql.validation.validation_context.MAX_FRAGMENT_WORK).
  • The budget of OverlappingFieldsCanBeMergedRule from CVE-2026-75507 counted only field comparisons, so some documents could still take quadratic time. It now covers all of the rule's work (see below).
  • max_tokens from CVE-2026-75508 was only checked after a whole run of comments had been read. It is now enforced while the comments are skipped.

Behavior changes:

  • Documents, fragment chains and variable values nested deeper than 200 levels are now rejected with a GraphQL error instead of raising RecursionError in the request path (#216). GraphQL.js has no such limit. Parsing gives "Syntax Error: Document is nested too deeply. Parsing aborted.", validation gives "Validation aborted.", variable values give "Variable values are nested too deeply." and execution without validation gives "Selections are nested too deeply. Execution aborted." Methods of Parser called directly and utilities such as separate_operations can still raise RecursionError, and inside of fields it stays a field error.
  • The limit also helps on PyPy, where exhausting the stack can crash the interpreter. This is a PyPy issue that newer PyPy versions do not fix yet. We recommend that users on PyPy upgrade GraphQL-core. Deep recursion elsewhere, for instance in your own code, can still run into the PyPy issue.
  • When the budget of OverlappingFieldsCanBeMergedRule is exhausted, the whole validation now stops with the errors found so far and "Validation aborted.", instead of only this rule stopping. The limit is now graphql.validation.rules.overlapping_fields_can_be_merged.MAX_COMPLEXITY_BUDGET, 500,000 units by default, and also counts comparisons of return type wrappers. MAX_FIELD_COMPARISONS is deprecated. If it is changed, the budget is two times its value and a DeprecationWarning is issued.
  • Conflict messages of this rule are now bounded. Descriptions are abbreviated after 1000 characters, and at most 20 locations are kept per side.
  • ValidationAbortedError is now a subclass of GraphQLError instead of RuntimeError, and validate() returns it as the last error when it aborts, also for the error limit.
  • A GraphQLError created while an exception is handled no longer adopts the traceback of that exception. When raised, it gets its own traceback and the handled exception as its context.
  • Non-integer numbers such as Decimal("2.5") now give a field error when serialized as Int instead of being truncated, as in GraphQL.js. Objects that are not numbers but can be converted to an int still work.
  • Only CRLF, LF and CR now count as line breaks in source locations and block strings, as in GraphQL.js (#294). This changes the locations of errors at a line start, which reported the previous line.

New features:

  • New option hide_suggestions of graphql, validate, execute, subscribe and related functions, as in version 3.3. It removes "Did you mean" from validation and input coercion errors.
  • New parser options max_lexical_tokens, max_comments and max_source_length for all parse functions and build_schema. max_lexical_tokens works as in GraphQL.js and does not count comments, so combine it with one of the others. max_source_length is measured in code points, where GraphQL.js uses UTF-16 code units.
  • max_tokens is deprecated in favor of these options, without a warning. Unlike in GraphQL.js it is not an alias: it keeps counting comments, so existing code keeps its protection. build_schema now accepts it too.
  • New option max_indent_depth of print_ast. From that depth on, nothing is indented and no newlines are inserted, while block strings keep theirs. Error messages now use at most 100 levels of indentation.

Bug fixes:

  • str(error) no longer raises IndexError for sources containing characters like VT, FF, NEL or U+2028, and print_ast formats block strings with these characters or trailing newlines like GraphQL.js (#295).
  • Conflicts between equal selection sets of fragments on different types were missed in documents parsed with no_location=True.
  • The default type resolver no longer leaves coroutines of is_type_of unawaited when a later is_type_of raises.
  • MapAsyncIterator.athrow keeps the original error if closing a source without athrow also fails.

Performance:

  • Printing is 57 to 62 percent faster on CPython on normal documents and 22 to 42 percent on PyPy.
  • Fields repeated in a selection set are validated faster, 69 ms instead of 102 ms for 1000 of them on CPython, and errors with many locations no longer scan the source for each of them.

Thanks to Nikhil Agrawal, Mettle Labs (@nikhilagrawalsf) and zx (@manus-use), who independently reported the problem with the introspection depth, to zx also for the reports on shared fragments and the budget, to @eliteaja11-dev for a variant of the latter, and to Zachariah Mithani (AploSec, @zachariah-mithani) for the report on comments. Thanks also to @devkral for reporting the issue with deep nesting, and to @arxhr007 for reporting and fixing the issue with line breaks.

Thanks to @jkimbo for sponsoring this project.

Don't miss a new graphql-core release

NewReleases is sending notifications on new releases.