Error handling

Problem Details

Problem Details for HTTP APIs (RFC 9457, obsoletes RFC7807) defines a simple JSON format to convey additional information about an error to an API consumer. This information complements the HTTP status codes [RFC7231].

For any problem occurred during processing, whether it be caused by the client or the server, the API provider supplies

  1. a suitable status code: 4xx for consumer or 5xx for server errors

  2. a RFC 9457 problem detail message

Rule: Use of RFC 9457 Problem Details [err-problem]

Any information on a problem SHOULD be provided in the Problem Detail format, as specified in Problem Details for HTTP APIs (RFC 9457, which obsoletes RFC 7807) :

  • the media type for problems SHOULD be application/problem+json

  • status: the HTTP status code

  • type: a unique identifier for the type of the problem that MUST remain stable over time. It can be used by API clients during problem handling.

  • title: a short summary of the problem type in English

  • instance: a unique identifier of the problem instance. It could be used to track the message for support purposes.

  • detail: consumer-friendly information about the specific failing request. It MAY be localized using language negotiation.

  • additional properties may be added to provide more structured information on the problem

Consumers SHOULD NOT parse the title or detail properties to extract information; additional properties are a more suitable and less error-prone way to obtain such information.

The Problem Details response body MAY be absent when the HTTP status code itself provides sufficient information (e.g. for 405 Method Not Allowed, 406 Not Acceptable or 415 Unsupported Media Type).

This guide applies following additional restrictions on the Problem Details structure:

  • type and instance SHOULD be specified as absolute URIs in order to avoid issues when resolving relative URIs (see Links)

  • The type property, a stable identifier for the type of problem, is REQUIRED instead of optional

  • a new optional href property SHOULD be used to provide a URI to human-readable documentation on the problem type instead of dereferencing the type value

Note that using href instead of type for documentation intentionally deviates from the recommendation in the RFC. href allows use of a URL for documentation purposes that may change over time, while type can be specified as a URN that must remain stable. This is especially useful for API-specific problem types for which the documentation URL may depend on technical aspects, like deployment environment.

Example 1. Example Problem response
POST /enterprises/abcd731645/employees
{
  "ssin": "98765432109",
  "givenName": "John",
  "familyName": "Doe"
}
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
BelGov-Trace-Id: d9e35127-e9b1-4201-a211-2b52e52508df
{
  "type": "urn:problem-type:belgif:badRequest",
  "href": "https://www.belgif.be/specification/rest/api-guide/problems/badRequest.html",
  "title": "Bad Request",
  "status": 400,
  "detail": "The input message is incorrect",
  "instance": "urn:uuid:123456-1234-1235-4567489798",
  "issues": [
    {
      "type": "urn:problem-type:belgif:input-validation:schemaViolation",
      "href": "https://www.belgif.be/specification/rest/api-guide/issues/schemaViolation.html",
      "title": "Input isn't valid with respect to schema",
      "detail": "enterpriseNumber abcd731645 should be numeric",
      "in": "path",
      "name": "enterpriseNumber",
      "value": "abcd731645"
    },
    {
      "type": "urn:problem-type:belgif:input-validation:referencedResourceNotFound",
      "href": "https://www.belgif.be/specification/rest/api-guide/issues/referencedResourceNotFound.html",
      "title": "Referenced resource not found",
      "detail": "No person with ssin '98765432109' exists",
      "in": "body",
      "name": "/ssin",
      "value": "98765432109"
    }
  ]
}
Problem Details JSON schema (from problem-v1.yaml)
    Problem:
      description: |
        A Problem Details object (RFC 9457).

        Additional properties specific to the problem type may be present.
      type: object
      properties:
        type:
          type: string
          format: uri
          description: An absolute URI that identifies the problem type
          default: about:blank  # kept for backwards-compatibility, type will be mandatory in problem-v2
        href:
          type: string
          format: uri
          description: An absolute URI that, when dereferenced, provides human-readable documentation for the problem type (e.g. using HTML).
        title:
          type: string
          description: A short summary of the problem type. Written in English and readable for engineers (usually not suited for non technical stakeholders and not localized).
          example: Service Unavailable
        status:
          type: integer
          format: int32
          description: The HTTP status code generated by the origin server for this occurrence of the problem.
          minimum: 400
          maximum: 600
          exclusiveMaximum: true
          example: 503
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence of the problem
        instance:
          type: string
          format: uri
          description: An absolute URI that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.
Rule: Problem type [prb-type]

Problem type SHOULD be specified as a URN in one of following formats:

  • urn:problem-type:<org>:<api>:<type>

  • urn:problem-type:<org>:<type>

with:

  • <org>: a short identifier for the organization

  • <api>: name of the API. It MAY be used for API-specific problem types

  • <type>: type of the problem in lowerCamelCase

A description of an API-specific problem type MAY be provided as a reference data resource : /refData/problemTypes/{problemType}. If provided, at least the HTML media type SHOULD be supported.

Reverse FQDN notation for <org> is not recommended in order to keep the identifiers short and readable.

Example 2. API-specific problem type
{
  "type": "urn:problem-type:exampleOrg:socialStatus:searchCriteriaTooWide",
  "href": "https://api.example.org/demo/v1.be/socialStatus/v2/refData/problemTypes/urn:problem-type:exampleOrg:socialStatus:searchCriteriaTooWide",
  "status": 400,
  "title": "Search criteria should be more specific",
  "detail": "Only one search parameter specified. Please specify at least two.",
  "instance": "urn:uuid:123e4567-e89b-12d3-a456-426614174000"
}
Rule: Error sanitization [err-sanit]

A problem MUST NOT leak sensitive implementation and infrastructure details. Providers must strip this information (e.g. DB error codes, internal hostnames, stacktraces) before returning the problem detail to the consumer.

E.g. this should not be returned to a client:

HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: application/problem+json
{
  "type": "urn:problem-type:belgif:internalServerError",
  "instance": "urn:uuid:ac19acc6-5e11-4b2a-8c10-f9680998d07a",
  "title": "Internal Server Error",
  "detail": "Unexpected error code 24879 in server product XYZ v1.0.1",
  "stackTrace": [  [
      "EJBException: java.lang.RuntimeException: Something horrible happened on the server",
      "org.jboss.as.ejb3.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:191)",
      "org.jboss.as.ejb3.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:282)",
      "org.jboss.as.ejb3.CMTTxInterceptor.required(CMTTxInterceptor.java:345)",
      "org.jboss.as.ejb3.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:243)"
    ],
    [
      "Caused by: java.lang.RuntimeException: Something horrible has happened on the server",
      "sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
      "sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)",
      "sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
      "java.lang.reflect.Method.invoke(Method.java:606)"
    ]
  ]
}
Rule: Default problem response in OpenAPI [prb-defaul]

Problem types that may occur on all or most operations of an API (e.g. a missing permission, an internal server error, request violates schema, …​) SHOULD NOT each be documented explicitly in its OpenAPI description, as this would clutter the spec and make it difficult to keep up to date.

Rather, a default Problem response SHOULD be added to each operation. Operation-specific problem types should still be documented.

Specifying a default problem response ensures compatibility with clients that perform strict OpenAPI validation on response messages.

Example 3. Default problem response (using ProblemResponse from problem-v1.yaml)
/orders/{orderId}/archive:
  post:
    summary: archive the order
    operationId: archiveOrder
    parameters:
    - "$ref": "#/components/schemas/OrderId"
    responses:
      "200":
        "$ref": "#/components/responses/OrderArchivedResponse"
      "409":
        description: Order can not be archived when it's not completed
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/InvalidStateProblem"
      default:
        "$ref": "./problem/v1/problem-v1.yaml#/components/responses/ProblemResponse"

Standardized problem types

A list of problem types is standardized in this guide for reuse across all REST APIs. They are defined as URNs of format urn:problem-type:belgif:<type>.

href links to descriptions of standardized problem types will change in the future to recommended format containing full problem type identifier without HTML extension. Current URLs will redirect.

The library belgif-rest-problem-java provides implementation support for these problem types when developing Java applications.

The standardized problem types are described in their individual pages in the annex:

Status code Problem type

400

urn:problem-type:belgif:badRequest

401

urn:problem-type:belgif:noAccessToken

401

urn:problem-type:belgif:invalidAccessToken

401

urn:problem-type:belgif:expiredAccessToken

403

urn:problem-type:belgif:missingScope

403

urn:problem-type:belgif:missingPermission

404

urn:problem-type:belgif:resourceNotFound

413

urn:problem-type:belgif:payloadTooLarge

429

urn:problem-type:belgif:tooManyRequests

429

urn:problem-type:belgif:tooManyFailedRequests

500

urn:problem-type:belgif:internalServerError

502

urn:problem-type:belgif:badGateway

503

urn:problem-type:belgif:serviceUnavailable

problem-v1.yaml provides a reusable InputValidationProblem schema that extends the Problem schema with a list of issues for use in badRequest and resourceNotFound problems. Following standard issue types are defined for badRequest:

Issue type

urn:problem-type:belgif:input-validation:schemaViolation

urn:problem-type:belgif:input-validation:invalidInput

urn:problem-type:belgif:input-validation:unknownInput

urn:problem-type:belgif:input-validation:referencedResourceNotFound