Skip to content

Init-time and Runtime Diagnostics

Some failures cannot be caught by static analysis: they depend on what you pass to a runtime accessor, or on calling one before domain.init() has run. Protean raises these as exceptions, and each one carries a stable code alongside its prose message, so an operator or an agent catching the exception gets the same machine-readable rationale and fix that a protean check finding carries.

These are the kind = "raise" codes. They are distinct from the Fitness Function Catalog, which lists the kind = "lint" codes that protean check reports at design time. Both sets live in one registry, protean.ir.diagnostics, so a code is a public identifier you can rely on: renaming or removing one is a breaking change.

A few of these failures are statically detectable (a duplicate database model, two elements sharing a name). They stay raise-only for now; the shared registry keeps the door open for a future protean check rule to surface them at design time under the same code.

Reading a coded exception

Every coded exception exposes four attributes:

from protean.exceptions import IncorrectUsageError

try:
    domain.view_for(SomeAggregate)
except IncorrectUsageError as exc:
    print(exc.code)       # "USAGE_NOT_A_PROJECTION"
    print(exc.location)   # "Domain.view_for"
    print(exc.rationale)  # why it fired, from the registry
    print(exc.fix)        # how to fix it, from the registry

code and location survive a pickle round-trip, so the code is intact when an exception crosses the outbox or broker boundary. An exception raised without a code leaves all four attributes None, so existing raise sites are unaffected.

Severity levels

Every code here is an error: the operation cannot proceed. (Advisory warning/info levels belong to the lint codes in the fitness-function catalog.)


Configuration

Failures resolving configuration or looking up a registered element by name.

CONFIG_AMBIGUOUS_ELEMENT_NAME

Category configuration
Level error
Exception ConfigurationError
Raised by Domain._get_element_by_name

Why. A short element name that matches more than one registered element cannot be resolved to a single element, so the lookup is ambiguous.

Fix. Look the element up by its fully qualified name to disambiguate, or rename one of the colliding elements.

CONFIG_ELEMENT_NOT_REGISTERED

Category configuration
Level error
Exception ConfigurationError
Raised by Domain._get_element_by_name, Domain._get_element_by_fully_qualified_name

Why. Resolving an element by name requires it to be registered with the domain; an unregistered name has nothing to resolve to.

Fix. Register the element with the domain before it is looked up, or correct the name to one that is registered.

CONFIG_EVENT_STORE_NOT_INITIALIZED

Category configuration
Level error
Exception ConfigurationError
Raised by Domain._require_event_store

Why. The event store is wired during domain.init(); using it before then leaves the store unset.

Fix. Call domain.init() before using the event store.

CONFIG_UNRESOLVED_ENV_VAR

Category configuration
Level error
Exception ConfigurationError
Raised by Config2._replace_env_var

Why. A ${VAR} placeholder in configuration is substituted from the environment at load time; with the variable unset and no default given, it resolves to nothing.

Fix. Set the environment variable in the runtime environment, or give the placeholder a default with ${VAR|default}.

Usage

Runtime misuse of an accessor: passing the wrong kind of element, a name string instead of the class, or an unregistered element.

USAGE_CACHE_BACKED_NO_REPOSITORY

Category usage
Level error
Exception IncorrectUsageError
Raised by Domain.repository_for

Why. A cache-backed projection is served from a cache, not a provider, so it has no repository.

Fix. Use cache_for() to write and view_for() to read a cache-backed projection; repository_for() is for provider-backed elements.

USAGE_DUPLICATE_DATABASE_MODEL

Category usage
Level error
Exception IncorrectUsageError
Raised by Domain._register_element

Why. An aggregate maps to one database model per database; registering a second model for the same aggregate and database makes the mapping ambiguous.

Fix. Register one database model per aggregate per database, or target a different database on the duplicate model.

USAGE_ELEMENT_NOT_REGISTERED

Category usage
Level error
Exception IncorrectUsageError
Raised by Domain.repository_for, Domain.view_for, Domain.connection_for, Domain.create_snapshot, Domain.create_snapshots

Why. A runtime accessor resolves the element it is given against the registry; an unregistered element, or a name string instead of the class, has no entry to resolve.

Fix. Pass a registered element class to the accessor, and register the element with the domain first.

USAGE_ENRICHER_NOT_CALLABLE

Category usage
Level error
Exception IncorrectUsageError
Raised by Domain.register_event_enricher, Domain.register_command_enricher, Domain.register_aggregate_enricher

Why. An enricher is invoked to augment a message or aggregate, so it has to be callable; a non-callable value cannot be invoked.

Fix. Register a callable (a function or a callable object) as the enricher.

USAGE_NOT_A_PROJECTION

Category usage
Level error
Exception IncorrectUsageError
Raised by Domain.view_for, Domain.connection_for

Why. view_for and connection_for operate on projections; an element of another type has no read view or projection connection.

Fix. Call the accessor with a projection, or use the accessor that matches the element's type.

USAGE_UNKNOWN_ELEMENT_TYPE

Category usage
Level error
Exception IncorrectUsageError
Raised by Domain.factory_for

Why. The domain builds elements through a fixed set of type factories; a type outside that set has no factory to build it.

Fix. Use one of the supported domain element types.

Unsupported

An operation the framework does not support for the element it was given.

UNSUPPORTED_ELEMENT_CLASS

Category unsupported
Level error
Exception NotSupportedError
Raised by Domain.register

Why. Only classes carrying a domain element_type can be registered; a plain class has no element type for the domain to register.

Fix. Decorate the class as a domain element (e.g. @domain.aggregate) before registering it, or register a valid element class.