Error codes
Every error class of relaybus has a readonly code on its instances, next to its name. The code is stable: once released it is never renamed or reused, so alerts, dashboards and retry rules can branch on it. Messages may change between versions; codes do not.
ts
import { RelayBusError } from '@relaybus/core';
try {
await bus.publish(new OrderPlaced({ orderId }));
} catch (error) {
if (error instanceof RelayBusError && error.code === 'RELAYBUS_TRANSACTION_REQUIRED') {
// publish inside a transaction
}
}Where codes appear
- Dead letters and retries. The
lastErrorof a delivery (bus.listDeliveries()) has acodewhen the failure was a relaybus error, for example a transport that could not publish. - Observer events. The
errorofonDeliveryRetryScheduled,onDeliveryDeadandonFailurecarries the samecode. - Broker dead letters. Kafka adds
relaybus-error-nameandrelaybus-error-codeto the records it copies to<topic>.dead; RabbitMQ addsx-relaybus-dead-letter-error-nameandx-relaybus-dead-letter-error-codeto the messages it moves to<queue>.dead. Both keep their reason header, and their log lines carryerrorName=andcode=. The code header is left out for errors that have no code. toErrorInfo(error)addscodefor relaybus errors only. Errors of your handlers, drivers and brokers keepname,messageandstackwithout acode, exactly as before.
The field is additive: records written before 0.3.0 have no code, so read it as optional.
Code scheme
RELAYBUS_ + the package for errors outside core (KAFKA_, POSTGRES_, RABBITMQ_) + the error in upper snake case. An error class you derive from RelayBusError yourself inherits RELAYBUS_ERROR unless it sets its own code.
Codes
| Code | Error class | Package | Meaning |
|---|---|---|---|
RELAYBUS_ERROR | RelayBusError | @relaybus/core | Base class; any relaybus error without a more specific code. |
RELAYBUS_CONFIGURATION | ConfigurationError | @relaybus/core | Invalid options passed to a relaybus component. |
RELAYBUS_CATALOG_UNKNOWN_EVENT | UnknownCatalogEventError | @relaybus/core | A catalog or catalog route gives a wire name to an event the catalog (or the route's selection) does not have. Extends ConfigurationError. |
RELAYBUS_ROUTE_DUPLICATE_EVENT | DuplicateRouteEventError | @relaybus/core | A catalog route sends an event to a destination another route already sends it to. Extends ConfigurationError. |
RELAYBUS_WIRE_TYPE_COLLISION | WireTypeCollisionError | @relaybus/core | One event type has two wire names on a transport, or two event types share one (catalogs, routes, codec wireTypes). Extends ConfigurationError. |
RELAYBUS_WIRE_TYPES_UNSUPPORTED | WireTypesUnsupportedError | @relaybus/core | Wire names were declared for a transport or codec that cannot map type names (use jsonEnvelope). Extends ConfigurationError. |
RELAYBUS_TRANSACTION_REQUIRED | TransactionRequiredError | @relaybus/core | publish ran outside a transaction with transactionMode: 'required'. |
RELAYBUS_TRANSACTION_TIMEOUT | TransactionTimeoutError | @relaybus/core | A bus.transaction or @RelayBusTransaction() method ran past transactionTimeout and was rolled back; usually a slow external call inside it. |
RELAYBUS_TRANSACTION_ISOLATION_CONFLICT | TransactionIsolationConflictError | @relaybus/core | A @RelayBusTransaction({ isolationLevel }) method ran inside a transaction that relaybus did not open at that level; the level of a running transaction cannot change. |
RELAYBUS_NON_RETRYABLE | NonRetryableError | @relaybus/core | A handler asked to dead-letter the delivery at once. |
RELAYBUS_EVENT_VALIDATION | EventValidationError | @relaybus/core | A payload failed its event schema. Never retried. |
RELAYBUS_INVALID_ENVELOPE | InvalidEnvelopeError | @relaybus/core | A message received from a broker is not a valid event. Never retried. |
RELAYBUS_LEASE_LOST | LeaseLostError | @relaybus/core | The worker no longer owns the delivery it was processing. |
RELAYBUS_HANDLER_TIMEOUT | HandlerTimeoutError | @relaybus/core | A handler did not settle within its timeout. Retried. |
RELAYBUS_DISPATCHER_STOPPED | DispatcherStoppedError | @relaybus/core | The bus stopped before the handler finished; the delivery is released. |
RELAYBUS_ATTEMPTS_EXHAUSTED | AttemptsExhaustedError | @relaybus/core | A delivery came back after its lease expired on its last attempt; dead-lettered without running. |
RELAYBUS_LIFECYCLE | LifecycleError | @relaybus/core | A lifecycle method was called in a state that does not allow it, such as starting a bus twice. |
RELAYBUS_DRAIN_INCOMPLETE | DrainIncompleteError | @relaybus/core | drain still found due deliveries after its maximum number of batches. |
RELAYBUS_KAFKA_INVALID_MESSAGE | InvalidKafkaMessageError | @relaybus/kafka | A Kafka record is not a valid event. Never retried. |
RELAYBUS_KAFKA_UNENCODABLE_EVENT | UnencodableEventError | @relaybus/kafka | An event cannot be written to Kafka. Never retried. |
RELAYBUS_KAFKA_PUBLISH_TIMEOUT | PublishTimeoutError | @relaybus/kafka | No broker ack within publishTimeout. The outbox retries. |
RELAYBUS_KAFKA_HANDLER_FAILED | HandlerFailedError | @relaybus/kafka | A handler failure handed back to the Kafka client. |
RELAYBUS_KAFKA_TRANSPORT_CLOSED | TransportClosedError | @relaybus/kafka | The transport was closed; it no longer publishes or subscribes. |
RELAYBUS_KAFKA_GROUP_JOIN_TIMEOUT | GroupJoinTimeoutError | @relaybus/kafka | The consumer did not join its group within startupTimeout. |
RELAYBUS_POSTGRES_RECONCILE_FAILED | ReconcileFailedError | @relaybus/postgres | A claim was refused while giving back an earlier failed claim still fails; the next claim retries. |
RELAYBUS_RABBITMQ_UNAVAILABLE | RabbitMqUnavailableError | @relaybus/rabbitmq | The broker cannot take or confirm a message right now. Retried. |
RELAYBUS_RABBITMQ_PUBLISH_REJECTED | RabbitMqPublishRejectedError | @relaybus/rabbitmq | The broker nacked a published message. Retried. |
RELAYBUS_RABBITMQ_UNROUTABLE_MESSAGE | UnroutableMessageError | @relaybus/rabbitmq | No queue is bound to the routing key. Retried. |
RELAYBUS_RABBITMQ_MALFORMED_MESSAGE | MalformedMessageError | @relaybus/rabbitmq | A received message is not a valid relaybus CloudEvent. Dead-lettered. |
RELAYBUS_RABBITMQ_UNSERIALIZABLE_PAYLOAD | UnserializablePayloadError | @relaybus/rabbitmq | A payload cannot be represented as JSON. Never retried. |
RELAYBUS_TESTING_CODEC_CONTRACT | CodecContractError | @relaybus/testing | A codec contract case does not match: mismatches lists one line per difference. Thrown in tests only. |
RELAYBUS_RABBITMQ_UNENCODABLE_EVENT | RabbitMqUnencodableEventError | @relaybus/rabbitmq | The codec cannot write the event (a reserved header name, a type the route does not carry). Never retried. |
RELAYBUS_RABBITMQ_AMQP_LIMIT_EXCEEDED | AmqpLimitExceededError | @relaybus/rabbitmq | A value exceeds an AMQP 0-9-1 protocol limit. Never retried. |
A test keeps this table in step with the code: adding, renaming or removing a code fails it until the change is deliberate.