2020-05-06 15:41:14 +02:00
---
title: Error Handling
---
2020-03-09 08:01:43 +01:00
As a highly extensible product, SCM-Manager offers at least three ways to interact with:
- the GUI,
- the REST API, and
- the Java API
2023-11-29 18:14:03 +01:00
Having these three layers, the error handling should be consistent among these. That is, as a developer I would not like
to have custom made error codes in the REST layer that I cannot find in the Java API. Furthermore it is essential to get
precise error messages with hints how to find a way out (if possible), not only for a programmer making interactive
calls, but also for other programs. Last but not least it should be easy for plugin developers to adapt the error
handling.
2020-03-09 08:01:43 +01:00
On the GUI layer, these information have to be translated into messages that can be easily handled.
Here are some example error cases:
*Use case*: Read the metadata for a branch
*Possible errors:*
2023-11-29 18:14:03 +01:00
- The repository is missing
- There is no such branch
- The user is not authorized to read the metadata
- The repository is corrupt on file system level
2020-03-09 08:01:43 +01:00
---
2023-11-29 18:14:03 +01:00
*Use case:* Create a new user
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
*Possible errors:*
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
- Invalid characters in name
- Missing mandatory property
- Conflict with an existing user
- Insufficient priviliges
2020-03-09 08:01:43 +01:00
---
*Use case:* Update the e-mail of a repository
*Possible errors:*
2023-11-29 18:14:03 +01:00
- The repository does not exist
- The repository was modified concurrently
- Invalid e-mail address
2020-03-09 08:01:43 +01:00
## Java API
2023-11-29 18:14:03 +01:00
In SCM-Manager we make heavy use of Java `Exception` s, not only for technical exceptions in the program flow like
reading corrupt file systems, but also for "user errors" like illegal values or requests for missing data.
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
These exceptions are handled by
JEE [`ExceptionMapper` ](https://docs.oracle.com/javaee/7/api/jakarta/ws/rs/ext/ExceptionMapper.html ) s. Doing so, it is
possible to concentrate on implementing the "happy path" without the need to explicitly handle error cases everywhere (
for example you do not have to check whether got `null` as a result). Nonetheless we still had to decide whether to use
checked or unchecked exceptions. We have chosen to use unchecked exceptions due to the following reasons:
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
- Checked exceptions would have had to be declared everywhere.
- A checked exception can somehow trigger a "I have to handle this though I don't know how" feeling that would be wrong,
because we do have mappers for these exceptions.
2020-03-09 08:01:43 +01:00
Therefore handling such an exception has to be a concious decision.
In the following we will introduce the exceptions we are using:
### Used exceptions
#### `NotFoundException`
A `NotFoundException` is thrown, whenever "things" where requested but were not found.
#### `AlreadyExistsException`
2023-11-29 18:14:03 +01:00
This exception is thrown whenever an entity cannot be created, because another entity with the same key identifyer
exists.
2020-03-09 08:01:43 +01:00
#### `ConcurrentModificationException`
2023-11-29 18:14:03 +01:00
When you try to modify an entity based on an outdated version, this exception is thrown. For entities like user, group
or repository the "last modified" timestamp of `ModelObject` is used to check this.
2020-03-09 08:01:43 +01:00
#### `NativeRepositoryAccessException`
2023-11-29 18:14:03 +01:00
Failures while accessing native repositories (most of the time) result in `java.io.IOException` s. To distinguish these
exceptions from other I/O errors like network exceptions and to make them unchecked, we wrap them
in `NativeRepositoryAccessException` .
2020-03-09 08:01:43 +01:00
#### `ResteasyViolationException`
2023-11-29 18:14:03 +01:00
Input validation is handled
using [RESTEasy's validation support ](https://docs.jboss.org/resteasy/docs/3.0.0.Final/userguide/html/Validation.html ).
Constraint violations result in `ResteasyViolationException` s.
2020-03-09 08:01:43 +01:00
#### All other runtime exceptions
2023-11-29 18:14:03 +01:00
All other `java.lang.RuntimeException` s can be treated as unexpected errors, that either hint to severe problems (eg.
disk access failures) or implementation errors. It is unlikely that these can be handled by the program gracefully. They
will be caught by a generic exception handler which will wrap them in a new exception providing further SCM specific
information.
2020-03-09 08:01:43 +01:00
#### Checked exceptions
2023-11-29 18:14:03 +01:00
Above we mentioned, that we want to use unchecked exceptions only. Therefore we have to wrap checked exceptions for
example created by libraries or frarmeworks to make them unchecked. Normally it is sufficiant to wrap them in a
RuntimeException using a proper message, except you plan to handle them somewhere else than at resource level (then it
would be appropriate to introduce a new exception class extending `RuntimeException` ).
2020-03-09 08:01:43 +01:00
### Enrichment of exceptions
#### Context
2023-11-29 18:14:03 +01:00
Most of these exceptions must provide information about _what_ could not have been found, updated, whatsoever. This is
necessary, because otherwise it may not be clear at what step of a potentionally complex process this exception occured.
Though this sounds easy, it has some complexity because for example the access of a file in a repository can fail on
many levels (the file is missing in the given revision, the revision is missing, or the repository itself is missing).
In these cases you have to know the complete access path (what file in what revision of what changeset in what
repository).
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
To ensure that this is done in a reproducable and consistent way, SCM-Manager will provide utility functions to creaate
such exceptions.
2020-03-09 08:01:43 +01:00
#### Transaction IDs
2023-11-29 18:14:03 +01:00
To be able to retrace the cause for exceptions, it is helpful to link log messages to these exceptions. To do so,
SCM-Manager introduces transaction ids that are generated for single requests or other related actions like the
processing of hooks or cron jobs. This transaction id will be part of every log message and every API response.
2020-03-09 08:01:43 +01:00
For http requests, this can be done using MDC filter.
#### Identification of exceptions
2023-11-29 18:14:03 +01:00
To be able to identify different types of exceptions even outside of the java ecosystem, each SCM-Manager exception
class will get a unique type id that will be created using the `DefaultKeyGenerator` during development. We chose to
generate these ids and not "human readable" ones to prevent collisions between plugins.
2020-03-09 08:01:43 +01:00
### Logging of exceptions
2023-11-29 18:14:03 +01:00
To be able to retrace errors a proper logging is indispensible. So we decided to use the following rules for logging
exceptions:
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
- Native SCM manager exceptions will be logged at log level `INFO` with their message, only. The complete stacktrace
will be logged at log level `DEBUG` .
- All other exceptions will be logged on level `WARN` with the complete stacktrace, because they indicate something
going wrong on a fundamental level.
2020-03-09 08:01:43 +01:00
## REST API
### Status codes
2023-11-29 18:14:03 +01:00
SCM-Manager uses [http status codes ](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes ) to identify types of
errors (and successes, that is) and doing so provides a first hint, what may have gone wrong:
2020-03-09 08:01:43 +01:00
| Status code | Principal error cause |
2020-03-31 17:28:30 +02:00
|-------------|-----------------------|
2020-03-09 08:01:43 +01:00
| 200 | No error, everything is fine |
| 201 | The item has been created without an error |
| 204 | The request has been processed without an error |
| 400 | Something is not valid with the data provided |
| 401 | Missing authentication (not logged in?) |
| 403 | Missing authorization |
| 404 | The thing you are looking does not exist |
2023-11-29 18:14:03 +01:00
| 409 | Your update was rejected because you relate to an outdated version (maybe this item was changed in the meantime) _
or_ the item could not be created because the key already exists |
2020-03-09 08:01:43 +01:00
| 500 | The "You are not to blame" error; something unexpected went wrong while processing the request |
### Further information
2023-11-29 18:14:03 +01:00
Whenever possible, an error response contains useful details about the error in a simple json format. These information
are _not_ translated, so this is the responsibility of the frontend.
2020-03-09 08:01:43 +01:00
| key | content | availability |
2020-03-31 17:28:30 +02:00
|-----|---------|--------------|
2020-03-09 08:01:43 +01:00
| transactionId | A unique id to link your request to log messages | always |
| errorCode | A code that can be used for translated error messages. To prevent the usage of the same codes in different exceptions we decided to use generated ids. | always |
| context | (repo/key, branch/key, ...) | optional |
| message | An english error message (not necessarily for end users) | always |
| url | A URL to a site providing further information about the error | optional |
Error objects will contain no stack traces.
2023-11-29 18:14:03 +01:00
For SCM exceptions, the message will be created from the message of the java exception. For other exceptions this will
be a generic message in most cases.
2020-03-09 08:01:43 +01:00
Here is an example, how a concrete exception may look like in a json response:
```json
{
"transactionId": "7D82atGf3",
"errorCode": "H823fFAt",
"context": [
2023-11-29 18:14:03 +01:00
{
"type": "repository",
"id": "scmmanager/test"
},
{
"type": "branch",
"id": "master"
},
{
"type": "file",
"id": ".gitignore"
}
],
2020-03-09 08:01:43 +01:00
"message": "file not found",
"url": "https://www.scm-manager.org/errors/H823fFAt"
}
```
### Missing resources (404)
2023-11-29 18:14:03 +01:00
The http status code 404 is a special case, because it is a fundamental status code that can be created on a lot of
events:
2020-03-09 08:01:43 +01:00
- Your proxy has a misconfiguration and you are talking with a static website instead of SCM-Manager
- You are using a path without a valid endpoint in SCM-Manager
- You are requesting a entity that does not exists
2023-11-29 18:14:03 +01:00
Some say, that you should not try to interpret the body of a 404 response, because the origin of the response cannot be
taken for granted. Nonetheless we decided to use this http status code to indicate requests for missing resources,
because in our view this is what most people would expect.
2020-03-09 08:01:43 +01:00
### Internal errors (500)
2023-11-29 18:14:03 +01:00
Internal errors boil down to the following message: An error occured, that could not be handled in a reasonable way by
the program. In these cases often only an administrator can help. Examples are out-of-memory errors, failing disk I/O,
timeouts accessing other services, or (to be honest) simple programming errors that have to be fixed in further
releases. To be able to trace these errors in the logs one can use the transaction ids.
2020-03-09 08:01:43 +01:00
## GUI
2023-11-29 18:14:03 +01:00
As an end user of the SCM-Manager I would not like to see confusing internals, but rather have a meaningful message in
my language of choice. Therefore it is necessary to identify error types on a fine level. This can be done using the
errorCode provided in each error object.
2020-03-09 08:01:43 +01:00
2023-11-29 18:14:03 +01:00
Basically we have to differentiate between errors the user can handle ("user errors") and technical exceptions. For user
errors a meaningful message can be generated giving hints to what the user has done "wrong". All other exceptions can be
handled by displaying a "sorry, this did not work as expected" message with the transaction id.
2020-03-09 08:01:43 +01:00
## Resources / Best Practices
2023-11-29 18:14:03 +01:00
While creating this concepts we tried to adhere to best practices considering APIs of Twitter, Facebook, Bing, Spotify
and others, as summarized in the following articles:
2020-03-09 08:01:43 +01:00
2020-03-31 17:28:30 +02:00
* [RESTful API Design: What About Errors? (Apigee) ](https://apigee.com/about/blog/technology/restful-api-design-what-about-errors )
* [Best Practices for API Error Handling (Nordic APIS) ](https://nordicapis.com/best-practices-api-error-handling/ )