eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

In this tutorial, we’ll learn about the error handling options in GraphQL. We’ll look at what the GraphQL spec says about the error responses. Consequently, we’ll develop an example of GraphQL error handling using Spring Boot.

2. Response per GraphQL Specification

As per the GraphQL specification, every request received must return a well-formed response. This well-formed response consists of the map of data or errors from the respective successful or unsuccessful requested operation. Additionally, a response may contain partial successful result data and field errors.

The key components of the response map are errors, data, and extensions.

The errors section in the response describes any failure during the requested operation. If no error occurs, the errors component must not be present in the response. In the next section, we’ll look into the different kinds of errors described in the specification.

The data section describes the result of the successful execution of the requested operation. If the operation is a query, this component is an object of query root operation type. On the other hand, if the operation is a mutation, this component is an object of the mutation root operation type.

If the requested operation fails even before the execution due to missing information, validation errors, or syntax errors, then the data component must not be present in the response. And if the operation fails during the execution of the operation with an unsuccessful result, then the data component must be null.

The response map may contain an additional component called extensions, which is a map object. The component facilitates the implementors to provide other custom contents in the response as they see fit. Hence, there are no additional restrictions on its content format.

If the data component isn’t present in the response, then the errors component must be present and must contain at least one error. Further, it should indicate the reasons for the failures.

Here’s an example of a GraphQL error:

mutation {
  addVehicle(vin: "NDXT155NDFTV59834", year: 2021, make: "Toyota", model: "Camry", trim: "XLE",
             location: {zipcode: "75024", city: "Dallas", state: "TX"}) {
    vin
    year
    make
    model
    trim
  }
}

The error response when a unique constraint is violated will look like:

{
  "data": null,
  "errors": [
    {
      "errorType": "DataFetchingException",
      "locations": [
        {
          "line": 2,
          "column": 5,
          "sourceName": null
        }
      ],
      "message": "Failed to add vehicle. Vehicle with vin NDXT155NDFTV59834 already present.",
      "path": [
        "addVehicle"
      ],
      "extensions": {
        "vin": "NDXT155NDFTV59834"
      }
    }
  ]
}

3. Errors Response Component per GraphQL Specification

The errors section in the response is a non-empty list of errors, each of which is a map.

3.1. Request Errors

As the name suggests, request errors may occur before the operation execution if there is any issue with the request itself. It may be due to request data parsing failure, request document validation, an unsupported operation, or invalid request values.

When a request error occurs, this indicates that execution has not begun, which means the data section in the response must not be present in the response. In other words, the response contains only the errors section.

Let’s see an example demonstrating the case of invalid input syntax:

query {
  searchByVin(vin: "error) {
    vin
    year
    make
    model
    trim
  }
}

Here’s the request error response for a syntax error, which in this case was a missing quote mark:

{
  "data": null,
  "errors": [
    {
      "message": "Invalid Syntax",
      "locations": [
        {
          "line": 5,
          "column": 8,
          "sourceName": null
        }
      ],
      "errorType": "InvalidSyntax",
      "path": null,
      "extensions": null
    }
  ]
}

3.2. Field Errors

Field errors, as the name suggests, may occur due to either failure to coerce the value into the expected type or an internal error during the value resolution of a particular field. It means that field errors occur during the execution of the requested operation.

In case of field errors, the execution of the requested operation continues and returns a partial result, meaning the data section of the response must be present along with all the field errors in the errors section.

Let’s look at another example:

query {
  searchAll {
    vin
    year
    make
    model
    trim
  }
}

This time, we’ve included the vehicle trim field, which is supposed to be non-nullable according to our GraphQL schema.

However, one of the vehicles’ information has a null trim value, so we’re getting back only partial data – the vehicles whose trim value is not null – along with the error:

{
  "data": {
    "searchAll": [
      null,
      {
        "vin": "JTKKU4B41C1023346",
        "year": 2012,
        "make": "Toyota",
        "model": "Scion",
        "trim": "Xd"
      },
      {
        "vin": "1G1JC1444PZ215071",
        "year": 2000,
        "make": "Chevrolet",
        "model": "CAVALIER VL",
        "trim": "RS"
      }
    ]
  },
  "errors": [
    {
      "message": "Cannot return null for non-nullable type: 'String' within parent 'Vehicle' (/searchAll[0]/trim)",
      "path": [
        "searchAll",
        0,
        "trim"
      ],
      "errorType": "DataFetchingException",
      "locations": null,
      "extensions": null
    }
  ]
}

3.3. Error Response Format

As we saw earlier, errors in the response are a collection of one or more errors. And, every error must contain a message key that describes the failure reasons so the client developer can make necessary corrections to avoid the error.

Each error may also contain a key called locations, which is a list of locations pointing to a line in the requested GraphQL document associated with an error. Each location is a map with keys: line and column, respectively, providing the line number and beginning column number of the associated element.

The other key that may be part of an error is called path. It provides the list of values from the root element traced to the particular element of the response that has the error. A path value can be a string representing the field name or index of the error element if the field value is a list. If the error is related to a field with an alias name, then the value in the path should be the alias name.

3.4. Handling Field Errors

Whether a field error is raised on a nullable or non-nullable field, we should handle it as if the field returned null and the error must be added to the errors list.

In the case of a nullable field, the field’s value in the response will be null but errors must contain this field error describing the failure reasons and other information, as seen in the earlier section.

On the other hand, the parent field handles the non-nullable field error. If the parent field is non-nullable, then the error handling is propagated until we reach a nullable parent field or the root element.

Similarly, if a list field contains a non-nullable type and one or more list elements return null, the whole list resolves to null. Additionally, if the parent field containing the list field is non-nullable, then the error handling is propagated until we reach a nullable parent or the root element.

For any reason, if multiple errors are raised for the same field during resolution, then for that field, we must add only one field error into errors.

4. Spring Boot GraphQL Libraries

Our Spring Boot application example uses the spring-boot-starter-graphql module, which brings in the required GraphQL dependencies.

We’re also using the spring-graphql-test module for related testing:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-graphql</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.graphql</groupId>
    <artifactId>spring-graphql-test</artifactId>
    <scope>test</scope>
</dependency>

5. Spring Boot GraphQL Error Handling

In this section, we’ll mainly cover GraphQL error handling in the Spring Boot application itself. We won’t cover the GraphQL Java and GraphQL Spring Boot application development.

In our Spring Boot application example, we’ll mutate or query for vehicles based on either location or VIN (Vehicle Identification Number). We’ll see different ways to implement error handling using this example.

In the following subsections, we’ll see how the Spring Boot module handles exceptions or errors.

5.1. GraphQL Response With Standard Exception

Generally, in a REST application, we create a custom runtime exception class by extending RuntimeException or Throwable:

public class InvalidInputException extends RuntimeException {
    public InvalidInputException(String message) {
        super(message);
    }
}

With this approach, we can see the GraphQL engine returns the following response:

{
  "errors": [
    {
      "message": "INTERNAL_ERROR for 2c69042a-e7e6-c0c7-03cf-6026b1bbe559",
      "locations": [
        {
          "line": 2,
          "column": 5
        }
      ],
      "path": [
        "searchByLocation"
      ],
      "extensions": {
        "classification": "INTERNAL_ERROR"
      }
    }
  ],
  "data": null
}

In the above error response, we can see that it doesn’t contain any details of the error.

By default, any exception during request processing is handled by the ExceptionResolversExceptionHandler class that implements the DataFetcherExceptionHandler interface from the GraphQL API. It allows the application to register one or more DataFetcherExceptionResolver components.

These resolvers are sequentially invoked until one of them is able to handle the exception and resolve it to a GraphQLError. If no resolvers are able to handle the exception then the exception is categorized as an INTERNAL_ERROR. It also contains the execution id and generic error message, as shown above.

5.2. GraphQL Response With Handled Exception

Now let’s see what the response will look like if we implement our custom exception handling.

First, we have another custom exception:

public class VehicleNotFoundException extends RuntimeException {
    public VehicleNotFoundException(String message) {
        super(message);
    }
}

DataFetcherExceptionResolver provides an async contract. However, in most cases, it is sufficient to extend DataFetcherExceptionResolverAdapter and override one of its resolveToSingleError or resolveToMultipleErrors methods that resolve exceptions synchronously.

Now, let’s implement this component and we can return a NOT_FOUND classification along with the exception message instead of the generic error:

@Component
public class CustomExceptionResolver extends DataFetcherExceptionResolverAdapter {

    @Override
    protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) {
        if (ex instanceof VehicleNotFoundException) {
            return GraphqlErrorBuilder.newError()
              .errorType(ErrorType.NOT_FOUND)
              .message(ex.getMessage())
              .path(env.getExecutionStepInfo().getPath())
              .location(env.getField().getSourceLocation())
              .build();
        } else {
            return null;
        }
    }
}

Here, we’ve created a GraphQLError with the appropriate classification and other error details to create a more useful response in the errors section of the JSON response:

{
  "errors": [
    {
      "message": "Vehicle with vin: 123 not found.",
      "locations": [
        {
          "line": 2,
          "column": 5
        }
      ],
      "path": [
        "searchByVin"
      ],
      "extensions": {
        "classification": "NOT_FOUND"
      }
    }
  ],
  "data": {
    "searchByVin": null
  }
}

An important detail of this error handling mechanism is that unresolved exceptions are logged at the ERROR level along with the executionId that correlates with the error sent to the client. Any resolved exceptions, as shown above, are logged at DEBUG level in the logs.

6. Conclusion

In this tutorial, we learned different types of GraphQL errors. We also looked at how to format the GraphQL errors per the specification. Later we implemented error handling in a Spring Boot application.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)