Handling errors

In this article:


    Attention   

     

    Introduction

    When an error occurs, the API responds with detailed information about what went wrong and what part of the request caused it. An error response can fall into one of two categories: Internal errors and validation errors.

    Regardless of the type of error that occurred, the response will always be structured in the same way, containing a message describing the problem, a category listing what type of error occurred, and a locations entry providing the position in the offending request which caused the error. Finally, a path entry is provided, which gives the path to the query or mutation in the request, which caused the error; this can be especially useful if multiple queries or mutations are batched together in one request.

    Also read: API Rate Limits

     

    Errors during mutations

    If any error occurs during a mutation, all changes performed by the request will be canceled. Therefore, if - for any reason - a mutation fails, your data will remain the same as if the mutation had not been executed at all. This ensures the integrity of your data and makes it clear to understand the state of the system at any time.

     

    Internal errors

    When an error occurs on our end, you will be presented with an error similar to the following:

    {
      "errors": [
        {
          "message": "Internal server error",
          "category": "internal",
          "locations": [
            {
              "line": 2,
              "column": 3
            }
          ],
          "path": [
            "orders"
          ]
        }
      ],
      "data": []
    }

     

    Validation errors

    Whenever a query or mutation is performed, which takes input, the provided input is validated to ensure that the resulting data is valid, ideally making it impossible to put your solution into an invalid or corrupted state. If input is deemed invalid, then the content field of the resulting payload will be null, and details on the validation errors are provided in the errors field.

    All errors in any errors field of a payload implement the ClientErrorInterface interface:

    
        interface ClientErrorInterface {
            field: [String!]!
            message: String!
            name: String!
        }
        

    Types implementing this interface are grouped by business domain, so that related queries and mutations use the same concrete error type. This is demonstrated in the following example, with PageTreeClientError as the concrete type.

    Each of these fields are explained in more detail in the following examples.

    Example: Creating a page

    In this example, we attempt to create a new page.

    Our GraphQL request is as follows:

     

    QUERY

    
                
        mutation pageCreate($input: PageCreateInput!) {
          pageCreate(input: $input) {
            content {
              id
            }
            errors {
              field
              message
              name
              code
              id
            }
          }
        }
        

    VARIABLES

    
                
        {
            "input": {
                "folderId": 1,
                "parentId": 1,
                "languageLayerAccess": [
                    1,
                    2
                ],
                "menuDisplaySettings": [
                    1
                ],
                "translations": [
                    {
                        "languageId": 1,
                        "data": {
                            "link": "pageLink1"
                        }
                    },
                    {
                        "languageId": 2,
                        "data": {
                            "title": "pageTitle2"
                        }
                    }
                ],
                "type": "TEXT",
                "userAccessSettings": [
                    1
                ]
            }
        }
        

    Response

    
            
        {
            "data": {
                "content": null,
                "errors": [
                    {
                        "field": [
                            "input",
                            "folderId"
                        ],
                        "message": "Unexpected 'folderId'. Expected exactly one of: ['folderId', 'parentId'].",
                        "name": "EXCLUSIVE_OR_UNEXPECTED_ERROR",
                        "code": "EXCLUSIVE_OR_UNEXPECTED_ERROR",
                        "id": "EXCLUSIVE_OR_UNEXPECTED_ERROR"
                    },
                    {
                        "field": [
                            "input",
                            "parentId"
                        ],
                        "message": "Unexpected 'parentId'. Expected exactly one of: ['folderId', 'parentId'].",
                        "name": "EXCLUSIVE_OR_UNEXPECTED_ERROR",
                        "code": "EXCLUSIVE_OR_UNEXPECTED_ERROR",
                        "id": "EXCLUSIVE_OR_UNEXPECTED_ERROR"
                    },
                    {
                        "field": [
                            "input",
                            "parentId"
                        ],
                        "message": "Page with id '123' does not exist.",
                        "name": "ENTITY_NOT_FOUND_ERROR",
                        "code": "ENTITY_NOT_FOUND_ERROR",
                        "id": "ENTITY_NOT_FOUND_ERROR"
                    },
                    {
                        "field": [
                            "input",
                            "translations"
                        ],
                        "message": "Missing required 'title' in primary language: 1",
                        "name": "MISSING_PRIMARY_TITLE_ERROR",
                        "code": "MISSING_PRIMARY_TITLE_ERROR",
                        "id": "MISSING_PRIMARY_TITLE_ERROR"
                    }
                ]
            }
        }
        

    This then means that our input violates 4 different (but not unique) constraints:

    1. input.folderId: Exactly one of folderId and parentId fields are expected.
    2. input.parentId: Exactly one of folderId and parentId fields are expected.
    3. input.parentId: The given ID of 123 doesn't refer to a page that exists.
    4. input.translations: We didn't provide a title translation in the primary language, this case language with id 1.

    There are a few things to note here:

    While 4 constraints on the input were violated, both (2) and (3) were associated with the same field in the input, and two of the violations were caused by the same constraint - but on two differed fields. Finally, while the absence of a `title` translation in a primary language *could* have had its field listed as `input.translations.0`, this was not the case; this is so that even if no translations for the primary language are provided, the context of the violation is still clear.

    What this also demonstrates is that the PageTreeClientError type includes two additional fields not present in ClientErrorInterface: name and id.

    The full definition of the PageTreeClientError is:

    
        interface ClientErrorInterface {
            field: [String!]!
            message: String!
            name: String!
        }
        

    The id field contains a unique machine-readable identifier for the error type. Currently, this will have the same value as the name field in many cases, however this will be a UUID in the future.

    The code field contains the error-code for errors of this type, and is an enumeration, which allows developers to inspect the schema and know exactly which errors can be expected from a given query or mutation.

    While it may seem superfluous to have both the name and code fields, the reasoning behind this is that having a string version of the code field allows API clients to write general fragment selects, such as:

    
        fragment ClientErrorFields on ClientErrorInterface {
          field
          message
          name
        }
        

    This can then be leveraged to simplify the above pageCreate mutation:

    
        mutation pageCreate($input: PageCreateInput!) {
          pageCreate(input: $input) {
            content {
              id
            }
            errors {
              ...ClientErrorFields
              code
              id
            }
          }
        }
    
        fragment ClientErrorFields on ClientErrorInterface {
          field
          message
          name
        }
        

    Validation errors (deprecated)

    Another type of error that can occur is a validation error. This occurs if some of the provided data is invalid. The following example demonstrates this by attempting to create a page inside a folder that does not exist:

    POST shop99999.mywebshop.io/api/graphql
    (Replace "shop99999" with your own shop number)

    
    mutation {
      pageCreate(input: {folderId: 123, type: text}) {
        id
      }
    }
    

    Response

    
    {
      "errors": [
        {
          "message": "The given data was invalid.",
          "category": "graphql",
          "locations": [
            {
              "line": 2,
              "column": 3
            }
          ],
          "path": [
            "pageCreate"
          ],
          "validation": {
            "input.folderId": [
              "validation.exists"
            ]
          }
        }
      ],
      "data": []
    }

    In the case of validation errors, the errors entry of the response also contains a validation section, which will enumerate all validation errors, indexed by the path to the invalid data in the input.