Skip to content

Exceptions

Django Ninja AIO CRUD provides a structured exception hierarchy for consistent error handling across all API endpoints.


Overview

All framework exceptions inherit from BaseException and carry a serializable error payload and an HTTP status code. Exception handlers registered on the NinjaAIO instance automatically convert them into JSON responses.

Python
from ninja_aio.exceptions import (
    BaseException,
    SerializeError,
    AuthError,
    NotFoundError,
    PydanticValidationError,
)

Exception Classes

BaseException

Base class for all framework exceptions.

Python
class BaseException(Exception):
    error: str | dict = ""
    status_code: int = 400

Constructor:

Python
BaseException(
    error: str | dict = None,
    status_code: int | None = None,
    details: str | None = None,
)
Parameter Type Description
error str \| dict Error payload. Strings are wrapped under the "error" key; dicts are used directly.
status_code int \| None HTTP status code. Defaults to 400.
details str \| None Optional detail message merged into the error dict under "details".

Example:

Python
# String error
exc = BaseException("Something went wrong", 400)
print(exc.error)  # {"error": "Something went wrong"}

# Dict error with details
exc = BaseException({"field": "invalid"}, details="must be positive")
print(exc.error)  # {"field": "invalid", "details": "must be positive"}

SerializeError

Raised when serialization of request or response payloads fails. Inherits directly from BaseException with the same interface.

Python
raise SerializeError("Invalid base64 encoding", 400)

AuthError

Raised when authentication or authorization fails. Inherits from BaseException.

Python
raise AuthError("Unauthorized", 401)

NotFoundError

Raised when a requested model instance cannot be found. Always returns HTTP 404.

Python
class NotFoundError(BaseException):
    status_code = 404
    error = "not found"
    use_verbose_name = getattr(
        settings, "NINJA_AIO_NOT_FOUND_ERROR_USE_VERBOSE_NAMES", True
    )

Constructor:

Python
NotFoundError(model: Model, details=None)

Error key format:

By default the error key is the model's verbose_name with spaces replaced by underscores:

Python
# Model with verbose_name = "blog post"
raise NotFoundError(BlogPost)
# {"blog_post": "not found"}

When NINJA_AIO_NOT_FOUND_ERROR_USE_VERBOSE_NAMES = False the error key is derived from the model class name converted to snake_case:

Python
# settings.py
NINJA_AIO_NOT_FOUND_ERROR_USE_VERBOSE_NAMES = False

raise NotFoundError(BlogPost)
# {"blog_post": "not found"}

raise NotFoundError(TestModelSerializer)
# {"test_model_serializer": "not found"}

NINJA_AIO_NOT_FOUND_ERROR_USE_VERBOSE_NAMES

Value Error key source Example
True (default) model._meta.verbose_name with spaces → _ {"blog_post": "not found"}
False model.__name__ converted to snake_case {"test_model_serializer": "not found"}

Configure in settings.py:

Python
# Use snake_case model class name in not-found errors
NINJA_AIO_NOT_FOUND_ERROR_USE_VERBOSE_NAMES = False

PydanticValidationError

Wraps a Pydantic ValidationError into a normalized 400 response.

Python
PydanticValidationError(details=None)

Response format:

JSON
{
  "error": "Validation Error",
  "details": [...]
}

Exception Handlers

Exception handlers are automatically registered when using NinjaAIO. You can also register them manually:

Python
from ninja_aio.exceptions import set_api_exception_handlers

api = NinjaAIO()
set_api_exception_handlers(api)
Exception type Handler Response code
BaseException _default_error From exc.status_code
JoseError _jose_error 401
ValidationError _pydantic_validation_error 400

Complete Example

Python
from ninja_aio.exceptions import NotFoundError, SerializeError

async def get_article(request, pk: int):
    try:
        article = await Article.objects.aget(pk=pk)
    except Article.DoesNotExist:
        raise NotFoundError(Article)  # {"article": "not found"}, 404

    return article


async def create_article(request, data):
    try:
        payload, customs = await util.parse_input_data(request, data)
    except SerializeError as e:
        # Already handled by NinjaAIO exception handlers
        raise

    return await Article.objects.acreate(**payload)

See Also