Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Platform

Reference

Errors and exceptions

Error classes, the 213 error code constants, the JSON error body, trace ids, and the mapping from exceptions to HTTP status codes in the Cluster ERP server.

This page lists the error classes and codes of Cluster ERP and how the server turns exceptions into HTTP responses. It covers core/errors.py, core/exceptions.py, and server/error_handler.py. The full list of codes with their causes, as a client sees them, is on API errors.

Scope and source

  • Defined in: src/cluster_erp/core/errors.py (AppError, code constants, factories), src/cluster_erp/core/exceptions.py (platform exceptions), src/cluster_erp/server/error_handler.py (install_error_handlers)
  • Count: 213 module-level string constants of the form NAME = "NAME" in core/errors.py (counted with grep -c -E '^[A-Z_0-9]+ = "'), in 23 commented groups; 6 factory functions; 7 exception classes in core/exceptions.py (counted with grep -c "^class")

The error body

Every handled error returns a JSON body built by _build_body (src/cluster_erp/server/error_handler.py:33-46):

{
 "error": {
 "code": "<CODE>",
 "message": "<developer message>",
 "trace_id": "<YYMMDD-NNN>",
 "details": {}
 }
}

details is present only when it is not empty. In debug mode the unhandled-exception handler adds debug_message and exception_type, and the mapped handlers add debug_message (src/cluster_erp/server/error_handler.py:305-308, src/cluster_erp/server/error_handler.py:345-347). debug_message carries at most the first line of the driver message, cut to 300 characters, never the SQL text (src/cluster_erp/server/error_handler.py:99-107).

Trace ids

_next_trace_id increments a per-day counter in the table trace_sequence and returns YYMMDD-NNN. If the database is unreachable it returns YYMMDD- with eight digits taken from a monotonic clock (src/cluster_erp/server/error_handler.py:49-70). The table comes from the migration feefe25508db_add_trace_sequence_table.py. Handlers store the trace id and error data on request.state; the activity-log middleware writes them to the error log (src/cluster_erp/server/error_handler.py:73-93, src/cluster_erp/server/middleware.py:638-659).

AppError

AppError(code, message, *, status_code=400, details=None) is the exception that services and routes raise (src/cluster_erp/core/errors.py:6-30). The code is machine-readable, the client maps it to a localised text, and the message is an English developer string (src/cluster_erp/core/errors.py:7-16).

Code groups

Group comment Codes Lines Examples
Auth 12 src/cluster_erp/core/errors.py:33-48 AUTH_TOKEN_EXPIRED, AUTH_PERMISSION_DENIED
Resource CRUD 3 src/cluster_erp/core/errors.py:50-53 RESOURCE_NOT_FOUND, RESOURCE_CONFLICT, RESOURCE_PROTECTED
Validation 7 src/cluster_erp/core/errors.py:55-75 VALIDATION_ERROR, FIELD_VALUE_INVALID
Business logic 5 src/cluster_erp/core/errors.py:77-82 UNIT_CONVERSION_FAILED, APPROVAL_INVALID_STATE
Currency 1 src/cluster_erp/core/errors.py:84-85 TCMB_SYNC_FAILED
CRM 14 src/cluster_erp/core/errors.py:87-104 RFQ_INVALID_STATUS, PRFQ_AWARD_INVALID
Quotations 9 src/cluster_erp/core/errors.py:106-117 QUOTE_INVALID_STATUS, QUOTE_INCOMPLETE
Sales Orders 9 src/cluster_erp/core/errors.py:119-129 ORDER_INVALID_STATUS, PDF_RENDERER_UNAVAILABLE
Projects 8 src/cluster_erp/core/errors.py:131-139 PROJECT_INVALID_STATUS, PROJECT_ACTIVITY_CYCLE
BOM 8 src/cluster_erp/core/errors.py:141-151 BOM_INVALID_STATUS, BOM_MAX_DEPTH_EXCEEDED
Design and Engineering 6 src/cluster_erp/core/errors.py:153-159 DESIGN_INVALID_STATUS, ECN_INVALID_STATUS
Products and Materials 13 src/cluster_erp/core/errors.py:161-179 PRODUCT_NOT_SELLABLE, PRODUCT_VERSION_MODEL_MISMATCH
Inventory 21 src/cluster_erp/core/errors.py:181-202 INVENTORY_INSUFFICIENT_STOCK, INVENTORY_NEGATIVE_STOCK
Production 32 src/cluster_erp/core/errors.py:204-264 see the file
Nesting 14 src/cluster_erp/core/errors.py:266-280 see the file
Costing 17 src/cluster_erp/core/errors.py:282-299 see the file
Procurement 20 src/cluster_erp/core/errors.py:301-321 SUBSTITUTION_GROUP_SINGLE_MEMBER, CRITICAL_MATERIAL_ALREADY_EXISTS
Concurrency 1 src/cluster_erp/core/errors.py:323-324 CONCURRENCY_VERSION_CONFLICT
External services 3 src/cluster_erp/core/errors.py:326-329 SMTP_NOT_CONFIGURED, SMTP_ERROR, FILE_NOT_FOUND_ON_DISK
Database 5 src/cluster_erp/core/errors.py:331-340 DB_INTEGRITY_ERROR, DB_UNIQUE_VIOLATION
Serialization 1 src/cluster_erp/core/errors.py:342-343 SERIALIZATION_ERROR
Runtime 3 src/cluster_erp/core/errors.py:345-348 TYPE_ERROR, VALUE_ERROR, TIMEOUT_ERROR
Server 1 src/cluster_erp/core/errors.py:350-351 INTERNAL_ERROR

Some modules define further codes in their own files, for example CURRENCY_UNKNOWN (src/cluster_erp/core/currencies.py:27) and UPLOAD_TYPE_REFUSED (src/cluster_erp/core/upload_policy.py:19). They are not counted above.

Factories

Function Code HTTP status Source
not_found(resource, resource_id=None) RESOURCE_NOT_FOUND 404 src/cluster_erp/core/errors.py:357-367
conflict(resource, field, value) RESOURCE_CONFLICT 409 src/cluster_erp/core/errors.py:370-376
protected(resource, reason="") RESOURCE_PROTECTED 400 src/cluster_erp/core/errors.py:379-385
permission_denied(permission) AUTH_PERMISSION_DENIED 403 src/cluster_erp/core/errors.py:388-394
privilege_escalation(missing_codes) AUTH_PRIVILEGE_ESCALATION 403 src/cluster_erp/core/errors.py:397-408
version_conflict(resource, expected, actual) and check_version(...) CONCURRENCY_VERSION_CONFLICT 409 src/cluster_erp/core/errors.py:411-430

Exception handlers

install_error_handlers(app, debug) registers the handlers below (src/cluster_erp/server/error_handler.py:200-398).

Exception Code HTTP status Source
AppError the error's own code the error's own status src/cluster_erp/server/error_handler.py:203-224
RequestValidationError VALIDATION_ERROR, with details.fields listing field and reason 422 src/cluster_erp/server/error_handler.py:226-246
HTTPException HTTP_<status>, or the code of a dictionary detail the exception's status src/cluster_erp/server/error_handler.py:248-270
SQLAlchemy DisconnectionError DB_CONNECTION_ERROR 503 src/cluster_erp/server/error_handler.py:128
SQLAlchemy TimeoutError (pool) DB_TIMEOUT 503 src/cluster_erp/server/error_handler.py:129-131
SQLAlchemy IntegrityError DB_UNIQUE_VIOLATION with details.constraint when a unique constraint is named, else DB_INTEGRITY_ERROR 409 src/cluster_erp/server/error_handler.py:132, src/cluster_erp/server/error_handler.py:352-398
SQLAlchemy DataError VALIDATION_ERROR 422 src/cluster_erp/server/error_handler.py:133-135
SQLAlchemy OperationalError DB_OPERATIONAL_ERROR 500 src/cluster_erp/server/error_handler.py:136
decimal.InvalidOperation VALIDATION_ERROR 422 src/cluster_erp/server/error_handler.py:142-148
Pydantic ValidationError SERIALIZATION_ERROR 500 src/cluster_erp/server/error_handler.py:150-155
TimeoutError TIMEOUT_ERROR 504 src/cluster_erp/server/error_handler.py:161
TypeError TYPE_ERROR 500 src/cluster_erp/server/error_handler.py:162
ValueError VALUE_ERROR 500 src/cluster_erp/server/error_handler.py:163
any other Exception INTERNAL_ERROR 500 src/cluster_erp/server/error_handler.py:272-310

A 503 response from the unhandled-exception handler carries Retry-After: 2 (src/cluster_erp/server/error_handler.py:309). Each mapped type gets its own handler so that Starlette's exception middleware handles it instead of the server-error middleware (src/cluster_erp/server/error_handler.py:312-318, src/cluster_erp/server/error_handler.py:394-398).

Platform exceptions

These classes in core/exceptions.py are raised by the module registry and the EventBus. They are not mapped to HTTP codes.

Class Parent Raised when Source
ClusterERPError Exception Base class src/cluster_erp/core/exceptions.py:4-5
ModuleError ClusterERPError Base class for module errors src/cluster_erp/core/exceptions.py:8-9
ModuleLoadError ModuleError A module cannot be imported or has no Module class src/cluster_erp/core/exceptions.py:12-16
ModuleNotRegisteredError ModuleError registry.get receives an unknown name src/cluster_erp/core/exceptions.py:19-22
EventBusError ClusterERPError Base class for bus errors src/cluster_erp/core/exceptions.py:25-26
QueryHandlerNotFoundError EventBusError A query has no handler src/cluster_erp/core/exceptions.py:29-32
DuplicateQueryHandlerError EventBusError A second handler is registered for a query type src/cluster_erp/core/exceptions.py:35-38

Constraints and validation

  • A request body larger than max_request_body_bytes is refused with HTTP 413 and code REQUEST_TOO_LARGE by a middleware, before any handler runs (src/cluster_erp/server/app.py:1396-1410). That code is not one of the constants in core/errors.py.
  • A RESOURCE_PROTECTED error uses HTTP 400, not 403 (src/cluster_erp/core/errors.py:379-385).

Terms introduced

Term Code identifier Definition Turkish term Source
application error AppError The exception that carries a machine-readable code, a message, a status, and details. uygulama hatası src/cluster_erp/core/errors.py:6
trace id trace_id A per-day sequence id that links an error response to its error-log row. izleme kimliği src/cluster_erp/server/error_handler.py:58-70

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13