nestjs/nest · warning · GraphQLError

Query is too complex: ${complexity}. Maximum allowed complex

Error message

Query is too complex: ${complexity}. Maximum allowed complexity: 20

What it means

A graphql-query-complexity guard implemented as a NestJS Apollo @Plugin (ComplexityPlugin). For every resolved operation it runs two estimators — fieldExtensionsEstimator() then simpleEstimator({ defaultComplexity: 1 }) — to score the query, and at sample/23-graphql-code-first/src/common/plugins/complexity.plugin.ts:31 it throws a GraphQLError when the score reaches 20. The plugin executes in didResolveOperation, i.e. BEFORE the resolvers run, so a rejected query never touches the data layer. Its purpose is DoS protection against catastrophically nested or wide queries.

Source

Thrown at sample/23-graphql-code-first/src/common/plugins/complexity.plugin.ts:31

  constructor(private gqlSchemaHost: GraphQLSchemaHost) {}

  async requestDidStart(): Promise<GraphQLRequestListener<any>> {
    const { schema } = this.gqlSchemaHost;

    return {
      async didResolveOperation({ request, document }) {
        const complexity = getComplexity({
          schema,
          operationName: request.operationName,
          query: document,
          variables: request.variables,
          estimators: [
            fieldExtensionsEstimator(),
            simpleEstimator({ defaultComplexity: 1 }),
          ],
        });
        if (complexity >= 20) {
          throw new GraphQLError(
            `Query is too complex: ${complexity}. Maximum allowed complexity: 20`,
          );
        }
        console.log('Query Complexity:', complexity);
      },
    };
  }
}

View on GitHub (pinned to 6ec0e2783d)

Solutions

  1. Set complexity directives (@complexity) on expensive/list fields via fieldExtensionsEstimator so wide lists cost proportionally and the threshold becomes meaningful.
  2. Raise the threshold (make it configurable via env: process.env.GQL_MAX_COMPLEXITY) rather than hard-coding 20.
  3. On the client, reduce the selection set — fetch only the fields you render, paginate list queries, and avoid deep nesting.
  4. If you intentionally want to disable the guard locally, gate the plugin behind an env flag or remove it from the module's provider list.

Example fix

// before
if (complexity >= 20) {
  throw new GraphQLError(`Query is too complex: ${complexity}. Maximum allowed complexity: 20`);
}

// after
const MAX = Number(process.env.GQL_MAX_COMPLEXITY ?? 100);
if (complexity > MAX) {
  throw new GraphQLError(`Query is too complex: ${complexity}. Maximum allowed complexity: ${MAX}`);
}
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: estimate complexity before sending, or introspect the schema cap.
// Crude heuristic: count selected fields; if it exceeds your budget, narrow the query.
const fieldCount = countSelectionFields(QUERY_STRING);
if (fieldCount > CLIENT_COMPLEXITY_BUDGET) {
  throw new Error(`Query too expensive (${fieldCount} fields) — narrow the selection`);
}

// Server-side: make the cap env-driven instead of hard-coding 20.
const MAX = Number(process.env.GQL_MAX_COMPLEXITY ?? 100);

Type guard

import { GraphQLError } from 'graphql';

function isComplexityError(e: unknown): boolean {
  return e instanceof GraphQLError
    && /too complex/i.test(e.message);
}

Try / catch

// In an Apollo Client / urql error link
onError(({ graphQLErrors }) => {
  graphQLErrors?.forEach(err => {
    if (/too complex/i.test(err.message)) {
      // tell the user to narrow the query, or auto-refetch a trimmed operation
    }
  });
});

Prevention

When it happens

Trigger: Any GraphQL operation whose summed field cost is >= 20: e.g., querying recipes() (a list) and selecting enough fields/relations that simpleEstimator's default cost of 1 per field adds up to 20, or a deeply nested selection set where fieldExtensionsEstimator has no per-field cost defined so everything falls back to 1.

Common situations: The threshold of 20 is intentionally low for the sample and trips on real-world list queries; fieldExtensionsEstimator is not configured with per-field complexity/depth multipliers, so list fields costing the same as scalars blow the budget fast; a client requests all recipes with full nesting; a React/Apollo client over-fetches after adding a new field.

Related errors


AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03). Data as JSON: /data/errors/317a98ca35e7d88a.json. Report an issue: GitHub.