Error Handling
OtterApi uses OtterApiException for all structured error responses.
Throw it from any BeforeSave or AfterSave hook to return a
machine-readable JSON error to the client. The middleware catches it automatically.
OtterApiException
Throwing from a hook
throw new OtterApiException(
code: "OUT_OF_STOCK",
message: "Cannot create order: the product is out of stock.",
statusCode: 422
);
Constructor parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
code | string | required | Machine-readable error code (e.g. "OUT_OF_STOCK") |
message | string | required | Human-readable error description |
statusCode | int | 400 | HTTP status code to return |
Response format
The middleware catches the exception and returns a JSON body:
HTTP Response
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"code": "OUT_OF_STOCK",
"message": "Cannot create order: the product is out of stock."
}
Built-in error codes
OtterApi itself throws OtterApiException in the following situations:
| Code | Status | When |
|---|---|---|
INVALID_BODY |
400 | Request body (POST / PUT) is null or empty |
INVALID_FILTER_OPERATOR |
400 | Client uses an operator not supported for the property type (e.g. filter[price][like]=foo) |
INVALID_JSON |
400 | Request body (POST / PUT / PATCH) contains invalid JSON, or filter[...][in] value is not a valid JSON array |
CONFLICT |
409 | Database unique or primary-key constraint violation |
DB_UPDATE_ERROR |
422 | Database update failed for another reason (FK violation, check constraint, etc.) |
KEYLESS_ENTITY |
405 | POST / PUT / PATCH / DELETE attempted on a keyless entity |
Validation errors (400)
OtterApi validates Data Annotations ([Required], [MaxLength], etc.)
on incoming POST and PUT bodies using the standard IObjectModelValidator.
Invalid requests return 400 Bad Request with the model state error details.
Example 400 response (missing required field)
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"Name": ["The Name field is required."]
}