1use std::borrow::Cow;
4use std::net::SocketAddr;
5use std::path::PathBuf;
6
7use aion::EngineError;
8use aion_core::{ActivityId, WorkflowId};
9use aion_proto::WireError;
10use aion_store::StoreError;
11use thiserror::Error;
12
13#[path = "error_engine.rs"]
14mod engine;
15#[path = "error_process_exit.rs"]
16mod process_exit;
17
18#[derive(Debug, Error)]
20pub enum ServerError {
21 #[error("configuration error: {message}")]
23 Config {
24 message: String,
26 },
27
28 #[error(
30 "unsafe store.data_dir `{}`: ancestor `{}` is not owner-controlled: {reason}; \
31 leave store.data_dir unset so it defaults beneath the private Aion home \
32 (`$AION_HOME`, default `$HOME/.aion`), or set a path whose ancestor chain is \
33 owner-only (a leading `~` expands against $HOME; a relative path resolves \
34 against the server's working directory)",
35 .data_root.display(),
36 .component.display()
37 )]
38 UnsafeDataRootAncestor {
39 data_root: PathBuf,
41 component: PathBuf,
43 reason: String,
45 },
46
47 #[error("{transport} transport failed at {address}: {message}")]
49 TransportBind {
50 transport: &'static str,
52 address: SocketAddr,
54 message: String,
56 },
57
58 #[error("{transport} transport task failed: {message}")]
60 Transport {
61 transport: &'static str,
63 message: String,
65 },
66
67 #[error("{listener} listener failed: {message}")]
69 SignalListener {
70 listener: &'static str,
72 message: String,
74 },
75
76 #[error("death note error: {message}")]
79 DeathNote {
80 message: String,
82 },
83
84 #[error("pid file error: {message}")]
86 PidFile {
87 message: String,
89 },
90
91 #[error("incarnation identity error: {message}")]
94 Incarnation {
95 message: String,
97 },
98
99 #[error("namespace error: {message}")]
101 Namespace {
102 message: String,
104 },
105
106 #[error("engine call failed: {source}")]
108 EngineCall {
109 #[from]
111 source: EngineError,
112 },
113
114 #[error("store backend failed: {source}")]
116 StoreBackend {
117 #[from]
119 source: StoreError,
120 },
121
122 #[error("stream failure: {failure}")]
124 Stream {
125 failure: StreamFailure,
127 },
128
129 #[error(
131 "worker dispatch failed for namespace {namespace}, activity type {activity_type}: {reason}"
132 )]
133 WorkerDispatch {
134 namespace: String,
136 activity_type: String,
138 reason: String,
140 },
141
142 #[error("worker connection lost during dispatch on {channel}: {detail}")]
155 WorkerConnectionLost {
156 channel: String,
158 detail: String,
160 },
161
162 #[error("worker connection busy during dispatch on {channel}: {detail}")]
173 WorkerBusy {
174 channel: String,
176 detail: String,
178 },
179
180 #[error(
183 "pending activity collision for workflow {workflow_id}, activity {activity_id}: \
184 a live responder already owns this execution site"
185 )]
186 PendingActivityCollision {
187 workflow_id: WorkflowId,
189 activity_id: ActivityId,
191 },
192
193 #[error(
196 "activity completion rejected for workflow {workflow_id}, activity {activity_id}: {reason}"
197 )]
198 ActivityCompletionRejected {
199 workflow_id: WorkflowId,
201 activity_id: ActivityId,
203 reason: CompletionRejectionReason,
205 },
206
207 #[error(
218 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
219 is already executing at this server"
220 )]
221 DeclaredAttemptCollision {
222 workflow_id: WorkflowId,
224 activity_id: ActivityId,
226 attempt: u32,
228 },
229
230 #[error(
240 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
241 refused: this server is draining and starts no new work"
242 )]
243 DrainingRefusedDeclaredAttempt {
244 workflow_id: WorkflowId,
246 activity_id: ActivityId,
248 attempt: u32,
250 },
251
252 #[error("{resource} lock was poisoned")]
254 LockPoisoned {
255 resource: &'static str,
257 },
258
259 #[error("wire error: {wire}")]
261 Wire {
262 wire: WireError,
264 },
265}
266
267#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
269pub enum CompletionRejectionReason {
270 #[error("completion token is missing (worker registration era is incompatible)")]
272 MissingCompletionToken,
273 #[error("no execution generation is currently accepting completion")]
275 NoCurrentGeneration,
276 #[error("completion token belongs to a stale execution generation")]
278 StaleGeneration,
279}
280
281#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
283pub enum StreamFailure {
284 #[error("consumer lagged behind bounded buffer")]
286 Lagged,
287 #[error("subscriber connection closed")]
289 Closed,
290 #[error("engine event stream closed")]
292 UpstreamClosed,
293}
294
295impl From<WireError> for ServerError {
296 fn from(wire: WireError) -> Self {
297 Self::Wire { wire }
298 }
299}
300
301impl ServerError {
302 #[must_use]
305 pub fn to_wire_error(&self) -> WireError {
306 match self {
307 Self::Config { .. }
308 | Self::UnsafeDataRootAncestor { .. }
309 | Self::TransportBind { .. }
310 | Self::Transport { .. }
311 | Self::SignalListener { .. }
312 | Self::DeathNote { .. }
313 | Self::PidFile { .. }
314 | Self::Incarnation { .. }
315 | Self::LockPoisoned { .. } => WireError::backend("server backend failure"),
316 Self::ActivityCompletionRejected { .. } => {
317 WireError::backend("stale activity completion rejected")
318 }
319 Self::PendingActivityCollision { .. } => {
320 WireError::backend("pending activity collision")
321 }
322 Self::DeclaredAttemptCollision { .. } => {
323 WireError::backend("declared command attempt collision")
324 }
325 Self::DrainingRefusedDeclaredAttempt { .. } => {
326 WireError::backend("declared command refused: server draining")
327 }
328 Self::WorkerDispatch { .. } => WireError::backend("worker dispatch failed"),
329 Self::WorkerConnectionLost { .. } => {
330 WireError::backend("worker connection lost during dispatch")
331 }
332 Self::WorkerBusy { .. } => WireError::backend("worker connection busy during dispatch"),
333 Self::Namespace { message } => WireError::namespace_denied(message.clone()),
334 Self::EngineCall { source } => wire_from_engine(source),
335 Self::StoreBackend { source } => wire_from_store(source),
336 Self::Stream { failure } => match failure {
337 StreamFailure::Lagged => WireError::lagged("subscriber lagged behind"),
338 StreamFailure::Closed | StreamFailure::UpstreamClosed => {
339 WireError::backend("event stream closed")
340 }
341 },
342 Self::Wire { wire } => wire.clone(),
343 }
344 }
345
346 #[must_use]
348 pub const fn is_config(&self) -> bool {
349 matches!(
350 self,
351 Self::Config { .. } | Self::UnsafeDataRootAncestor { .. }
352 )
353 }
354
355 #[must_use]
357 pub fn namespace_denied(message: impl Into<String>) -> Self {
358 Self::Namespace {
359 message: message.into(),
360 }
361 }
362
363 #[must_use]
371 pub fn placement_admission_denied(
372 namespace: &str,
373 worker_node: Option<&str>,
374 required: &std::collections::BTreeSet<String>,
375 ) -> Self {
376 let node = worker_node.unwrap_or("none");
377 let required = required
378 .iter()
379 .map(String::as_str)
380 .collect::<Vec<_>>()
381 .join(", ");
382 Self::namespace_denied(format!(
383 "worker registration rejected: namespace {namespace} is Pinned to node label(s) \
384 [{required}] but the worker advertises node {node}, which is not in the required set"
385 ))
386 }
387
388 #[must_use]
391 pub fn deploy_denied(message: impl Into<String>) -> Self {
392 Self::Wire {
393 wire: WireError::deploy_denied(message),
394 }
395 }
396
397 #[must_use]
399 pub const fn lagged_stream() -> Self {
400 Self::Stream {
401 failure: StreamFailure::Lagged,
402 }
403 }
404
405 #[must_use]
407 pub fn worker_dispatch(
408 namespace: impl Into<String>,
409 activity_type: impl Into<String>,
410 reason: impl Into<String>,
411 ) -> Self {
412 Self::WorkerDispatch {
413 namespace: namespace.into(),
414 activity_type: activity_type.into(),
415 reason: reason.into(),
416 }
417 }
418
419 #[must_use]
422 pub fn worker_connection_lost(channel: impl Into<String>, detail: impl Into<String>) -> Self {
423 Self::WorkerConnectionLost {
424 channel: channel.into(),
425 detail: detail.into(),
426 }
427 }
428
429 #[must_use]
435 pub const fn is_worker_connection_lost(&self) -> bool {
436 matches!(self, Self::WorkerConnectionLost { .. })
437 }
438
439 #[must_use]
442 pub fn worker_busy(channel: impl Into<String>, detail: impl Into<String>) -> Self {
443 Self::WorkerBusy {
444 channel: channel.into(),
445 detail: detail.into(),
446 }
447 }
448
449 #[must_use]
456 pub const fn is_worker_busy(&self) -> bool {
457 matches!(self, Self::WorkerBusy { .. })
458 }
459
460 #[must_use]
462 pub const fn lock_poisoned(resource: &'static str) -> Self {
463 Self::LockPoisoned { resource }
464 }
465}
466
467#[derive(Clone)]
469pub struct ErrorTraceFields<'a> {
470 pub error_type: Cow<'a, str>,
472 pub store_error_type: Option<&'static str>,
474 pub reason: &'a dyn std::fmt::Display,
476}
477
478impl<'a> ErrorTraceFields<'a> {
479 fn plain(error_type: &'static str, reason: &'a dyn std::fmt::Display) -> Self {
481 Self {
482 error_type: Cow::Borrowed(error_type),
483 store_error_type: None,
484 reason,
485 }
486 }
487}
488
489impl ServerError {
490 #[must_use]
492 pub fn trace_fields(&self) -> ErrorTraceFields<'_> {
493 match self {
494 Self::Config { message } => ErrorTraceFields::plain("Config", message),
495 Self::UnsafeDataRootAncestor { reason, .. } => {
496 ErrorTraceFields::plain("UnsafeDataRootAncestor", reason)
497 }
498 Self::TransportBind { message, .. } => {
499 ErrorTraceFields::plain("TransportBind", message)
500 }
501 Self::Transport { message, .. } => ErrorTraceFields::plain("Transport", message),
502 Self::SignalListener { message, .. } => {
503 ErrorTraceFields::plain("SignalListener", message)
504 }
505 Self::PidFile { message } => ErrorTraceFields::plain("PidFile", message),
506 Self::Incarnation { message } => ErrorTraceFields::plain("Incarnation", message),
507 Self::DeathNote { message } => ErrorTraceFields::plain("DeathNote", message),
508 Self::Namespace { message } => ErrorTraceFields::plain("Namespace", message),
509 Self::EngineCall { source } => engine_trace_fields(source),
510 Self::StoreBackend { source } => store_trace_fields(source),
511 Self::Stream { failure } => ErrorTraceFields::plain("Stream", failure),
512 Self::WorkerDispatch { reason, .. } => {
513 ErrorTraceFields::plain("WorkerDispatch", reason)
514 }
515 Self::WorkerConnectionLost { detail, .. } => {
516 ErrorTraceFields::plain("WorkerConnectionLost", detail)
517 }
518 Self::WorkerBusy { detail, .. } => ErrorTraceFields::plain("WorkerBusy", detail),
519 Self::PendingActivityCollision { activity_id, .. } => {
520 ErrorTraceFields::plain("PendingActivityCollision", activity_id)
521 }
522 Self::DeclaredAttemptCollision { activity_id, .. } => {
523 ErrorTraceFields::plain("DeclaredAttemptCollision", activity_id)
524 }
525 Self::DrainingRefusedDeclaredAttempt { activity_id, .. } => {
526 ErrorTraceFields::plain("DrainingRefusedDeclaredAttempt", activity_id)
527 }
528 Self::ActivityCompletionRejected { reason, .. } => {
529 ErrorTraceFields::plain("ActivityCompletionRejected", reason)
530 }
531 Self::LockPoisoned { resource } => ErrorTraceFields::plain("LockPoisoned", resource),
532 Self::Wire { wire } => ErrorTraceFields {
533 error_type: wire
534 .error_type
535 .as_deref()
536 .map_or_else(|| Cow::Borrowed(wire.code.as_str()), Cow::Borrowed),
537 store_error_type: None,
538 reason: wire,
539 },
540 }
541 }
542}
543
544fn never_alive_error_type(source: &EngineError) -> &'static str {
556 match source {
557 EngineError::TerminalWriterUnavailable { .. } => "TerminalWriterUnavailable",
558 EngineError::TerminalWriterHeld { .. } => "TerminalWriterHeld",
559 EngineError::RunIsRecoverable { .. } => "RunIsRecoverable",
560 EngineError::NoResidencyVerdict { .. } => "NoResidencyVerdict",
561 _ => "EngineError",
562 }
563}
564
565fn durability_trace_fields<'a>(
571 durability: &'a aion::durability::DurabilityError,
572 source: &'a EngineError,
573) -> ErrorTraceFields<'a> {
574 match durability {
575 aion::durability::DurabilityError::Store(store) => store_trace_fields(store),
576 aion::durability::DurabilityError::NonDeterminism(_)
577 | aion::durability::DurabilityError::HistoryShape { .. }
578 | aion::durability::DurabilityError::SearchAttribute(_) => {
579 simple_engine_fields("Durability", source)
580 }
581 aion::durability::DurabilityError::EngineTaskEpochClosed { .. } => {
587 simple_engine_fields("EngineTaskEpochClosed", source)
588 }
589 }
590}
591
592fn engine_trace_fields(source: &EngineError) -> ErrorTraceFields<'_> {
593 match source {
594 EngineError::WorkflowNotFound { .. } => simple_engine_fields("WorkflowNotFound", source),
595 EngineError::TerminalWriterUnavailable { .. }
597 | EngineError::TerminalWriterHeld { .. }
598 | EngineError::RunIsRecoverable { .. }
599 | EngineError::NoResidencyVerdict { .. } => {
600 simple_engine_fields(never_alive_error_type(source), source)
601 }
602 EngineError::InvalidState { .. } => simple_engine_fields("InvalidState", source),
603 EngineError::ScheduleNotFound { .. } => simple_engine_fields("ScheduleNotFound", source),
604 EngineError::ShuttingDown => simple_engine_fields("ShuttingDown", source),
605 EngineError::EngineTaskEpochClosed { .. } => {
606 simple_engine_fields("EngineTaskEpochClosed", source)
607 }
608 EngineError::Store(store) => store_trace_fields(store),
609 EngineError::Durability(durability) => durability_trace_fields(durability, source),
610 EngineError::MissingStore => simple_engine_fields("MissingStore", source),
611 EngineError::MissingVisibilityStore => {
612 simple_engine_fields("MissingVisibilityStore", source)
613 }
614 EngineError::ConflictingEventPublisher => {
615 simple_engine_fields("ConflictingEventPublisher", source)
616 }
617 EngineError::EventStreaming(_) => simple_engine_fields("EventStreaming", source),
618 EngineError::Load { .. } => simple_engine_fields("Load", source),
619 EngineError::UnenforceableContract { .. } => {
620 simple_engine_fields("UnenforceableContract", source)
621 }
622 EngineError::UnknownVersion { .. } => simple_engine_fields("UnknownVersion", source),
623 EngineError::VersionPinned { .. } => simple_engine_fields("VersionPinned", source),
624 EngineError::RouteActive { .. } => simple_engine_fields("RouteActive", source),
625 EngineError::ManifestMismatch { .. } => simple_engine_fields("ManifestMismatch", source),
626 EngineError::Package(_) => simple_engine_fields("Package", source),
627 EngineError::ContractIdentity { .. } => simple_engine_fields("ContractIdentity", source),
628 EngineError::NoQueueDeclaration { .. } => {
629 simple_engine_fields("NoQueueDeclaration", source)
630 }
631 EngineError::StartInputRefused { .. } => simple_engine_fields("StartInputRefused", source),
632 EngineError::SignalRefused { .. } => simple_engine_fields("SignalRefused", source),
633 EngineError::Schedule { .. } => simple_engine_fields("Schedule", source),
634 EngineError::Runtime { .. } => simple_engine_fields("Runtime", source),
635 EngineError::Gate3BifReplacementMissing { .. } => {
636 simple_engine_fields("Gate3BifReplacementMissing", source)
637 }
638 EngineError::StartupRecoveryNotDeferred => {
639 simple_engine_fields("StartupRecoveryNotDeferred", source)
640 }
641 EngineError::StartupRecoveryAlreadyRan => {
642 simple_engine_fields("StartupRecoveryAlreadyRan", source)
643 }
644 EngineError::StartupCatchupBeforeWorkflowRecovery => {
645 simple_engine_fields("StartupCatchupBeforeWorkflowRecovery", source)
646 }
647 EngineError::StartupRecoverySlotPoisoned => {
648 simple_engine_fields("StartupRecoverySlotPoisoned", source)
649 }
650 EngineError::CleanupExecutorPoisoned => {
651 simple_engine_fields("CleanupExecutorPoisoned", source)
652 }
653 EngineError::CleanupExecutorShutdownTimedOut { .. } => {
654 simple_engine_fields("CleanupExecutorShutdownTimedOut", source)
655 }
656 EngineError::RunNotInHistory { .. } => simple_engine_fields("RunNotInHistory", source),
657 EngineError::ProcessExitRegistryPoisoned => {
658 simple_engine_fields("ProcessExitRegistryPoisoned", source)
659 }
660 EngineError::ProcessExitOwnershipPoisoned { .. } => {
661 simple_engine_fields("ProcessExitOwnershipPoisoned", source)
662 }
663 EngineError::ProcessExitStatePoisoned { .. }
664 | EngineError::ProcessExitSubscriptionUnavailable
665 | EngineError::ProcessExitDrainerSpawn { .. }
666 | EngineError::ProcessExitDrainerPoisoned
667 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
668 | EngineError::ProcessExitEventStreamDisconnected
669 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
670 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_trace(source),
671 EngineError::ProcessExitCallbackDispatcherPoisoned
672 | EngineError::ProcessExitCallbackDispatcherUnavailable
673 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
674 process_exit::callback_trace(source)
675 }
676 EngineError::ProcessExitAlreadyTerminal { .. } => {
677 simple_engine_fields("ProcessExitAlreadyTerminal", source)
678 }
679 EngineError::ActivityDeliveryPoisoned { .. } => {
680 simple_engine_fields("ActivityDeliveryPoisoned", source)
681 }
682 EngineError::RegistryPoisoned => simple_engine_fields("RegistryPoisoned", source),
683 EngineError::CatalogPoisoned => simple_engine_fields("CatalogPoisoned", source),
684 EngineError::NifRegistration { .. } => simple_engine_fields("NifRegistration", source),
685 EngineError::SignalRouter(_) => simple_engine_fields("SignalRouter", source),
686 EngineError::Query(query) => simple_engine_fields(engine::query_error_type(query), source),
687 }
688}
689
690fn simple_engine_fields<'a>(
691 error_type: &'static str,
692 source: &'a EngineError,
693) -> ErrorTraceFields<'a> {
694 ErrorTraceFields {
695 error_type: Cow::Borrowed(error_type),
696 store_error_type: None,
697 reason: source,
698 }
699}
700
701fn store_trace_fields(source: &StoreError) -> ErrorTraceFields<'_> {
702 ErrorTraceFields {
703 error_type: Cow::Borrowed("StoreError"),
704 store_error_type: Some(engine::store_error_type(source)),
705 reason: source,
706 }
707}
708
709fn wire_from_engine(source: &EngineError) -> WireError {
710 use EngineError as E;
711 use engine::backend_wire as backend;
712
713 match source {
714 EngineError::WorkflowNotFound { .. } => {
715 WireError::not_found_with_type("WorkflowNotFound", source.to_string())
716 }
717 EngineError::InvalidState { reason } => engine::invalid_state_wire(reason),
719 E::TerminalWriterUnavailable { .. }
725 | E::TerminalWriterHeld { .. }
726 | E::RunIsRecoverable { .. }
727 | E::NoResidencyVerdict { .. } => engine::invalid_state_wire(&source.to_string())
728 .with_error_type(never_alive_error_type(source)),
729 EngineError::ScheduleNotFound { .. } => {
730 WireError::not_found_with_type("ScheduleNotFound", source.to_string())
731 }
732 EngineError::ShuttingDown => {
733 WireError::not_running_with_type("ShuttingDown", source.to_string())
734 }
735 E::EngineTaskEpochClosed { .. } => backend("EngineTaskEpochClosed", source),
756 EngineError::Store(store) => wire_from_store(store),
757 EngineError::Durability(durability) => engine::durability_wire(durability, source),
758 E::MissingStore => backend("MissingStore", source),
759 E::MissingVisibilityStore => backend("MissingVisibilityStore", source),
760 E::ConflictingEventPublisher => backend("ConflictingEventPublisher", source),
761 E::EventStreaming(_) => backend("EventStreaming", source),
762 E::Load { .. } => backend("Load", source),
763 EngineError::UnenforceableContract { .. } => {
766 WireError::invalid_input(source.to_string()).with_error_type("UnenforceableContract")
767 }
768 EngineError::UnknownVersion { .. } => {
770 WireError::not_found_with_type("UnknownVersion", source.to_string())
771 }
772 EngineError::VersionPinned { .. } => {
773 WireError::version_pinned(source.to_string()).with_error_type("VersionPinned")
774 }
775 EngineError::RouteActive { .. } => {
776 WireError::version_pinned(source.to_string()).with_error_type("RouteActive")
777 }
778 EngineError::ManifestMismatch { .. } => {
779 WireError::invalid_input(source.to_string()).with_error_type("ManifestMismatch")
780 }
781 E::Package(_) => backend("Package", source),
782 E::ContractIdentity { .. } => engine::contract_refusal_wire("ContractIdentity", source),
783 E::NoQueueDeclaration { .. } => engine::contract_refusal_wire("NoQueueDeclaration", source),
784 E::StartInputRefused { .. } => engine::declared_contract_wire("StartInputRefused", source),
785 E::SignalRefused { .. } => engine::declared_contract_wire("SignalRefused", source),
786 EngineError::Schedule { .. } => backend("Schedule", source),
787 E::Runtime { .. } => backend("Runtime", source),
788 E::Gate3BifReplacementMissing { .. } => backend("Gate3BifReplacementMissing", source),
789 E::StartupRecoveryNotDeferred => backend("StartupRecoveryNotDeferred", source),
792 E::StartupRecoveryAlreadyRan => backend("StartupRecoveryAlreadyRan", source),
793 E::StartupCatchupBeforeWorkflowRecovery => {
794 backend("StartupCatchupBeforeWorkflowRecovery", source)
795 }
796 E::StartupRecoverySlotPoisoned => backend("StartupRecoverySlotPoisoned", source),
797 E::CleanupExecutorPoisoned => backend("CleanupExecutorPoisoned", source),
798 E::CleanupExecutorShutdownTimedOut { .. } => {
799 backend("CleanupExecutorShutdownTimedOut", source)
800 }
801 E::RunNotInHistory { .. } => backend("RunNotInHistory", source),
807 E::ProcessExitRegistryPoisoned => backend("ProcessExitRegistryPoisoned", source),
808 E::ProcessExitOwnershipPoisoned { .. } => backend("ProcessExitOwnershipPoisoned", source),
809 EngineError::ProcessExitStatePoisoned { .. }
810 | EngineError::ProcessExitSubscriptionUnavailable
811 | EngineError::ProcessExitDrainerSpawn { .. }
812 | EngineError::ProcessExitDrainerPoisoned
813 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
814 | EngineError::ProcessExitEventStreamDisconnected
815 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
816 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_wire(source),
817 EngineError::ProcessExitCallbackDispatcherPoisoned
818 | EngineError::ProcessExitCallbackDispatcherUnavailable
819 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
820 process_exit::callback_wire(source)
821 }
822 E::ProcessExitAlreadyTerminal { .. } => backend("ProcessExitAlreadyTerminal", source),
823 E::ActivityDeliveryPoisoned { .. } => backend("ActivityDeliveryPoisoned", source),
824 E::CatalogPoisoned => backend("CatalogPoisoned", source),
825 E::RegistryPoisoned => backend("RegistryPoisoned", source),
826 E::NifRegistration { .. } => backend("NifRegistration", source),
827 E::SignalRouter(_) => backend("SignalRouter", source),
828 EngineError::Query(query) => engine::query_wire(query, source),
829 }
830}
831
832fn wire_from_store(source: &StoreError) -> WireError {
833 match source {
834 StoreError::SequenceConflict { .. } => WireError::new_with_type(
835 aion_proto::WireErrorCode::SequenceConflict,
836 "SequenceConflict",
837 source.to_string(),
838 ),
839 StoreError::NotFound { .. } => {
840 WireError::not_found_with_type("NotFound", source.to_string())
841 }
842 StoreError::NotOwner { .. } => {
843 WireError::not_owner(source.to_string()).with_error_type("NotOwner")
844 }
845 StoreError::Backend(_) => WireError::backend_with_type("Backend", source.to_string()),
846 StoreError::Serialization(_) => {
847 WireError::backend_with_type("Serialization", source.to_string())
848 }
849 }
850}
851
852#[cfg(test)]
853#[path = "error_tests.rs"]
854mod tests;