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("namespace error: {message}")]
86 Namespace {
87 message: String,
89 },
90
91 #[error("engine call failed: {source}")]
93 EngineCall {
94 #[from]
96 source: EngineError,
97 },
98
99 #[error("store backend failed: {source}")]
101 StoreBackend {
102 #[from]
104 source: StoreError,
105 },
106
107 #[error("stream failure: {failure}")]
109 Stream {
110 failure: StreamFailure,
112 },
113
114 #[error(
116 "worker dispatch failed for namespace {namespace}, activity type {activity_type}: {reason}"
117 )]
118 WorkerDispatch {
119 namespace: String,
121 activity_type: String,
123 reason: String,
125 },
126
127 #[error("worker connection lost during dispatch on {channel}: {detail}")]
140 WorkerConnectionLost {
141 channel: String,
143 detail: String,
145 },
146
147 #[error("worker connection busy during dispatch on {channel}: {detail}")]
158 WorkerBusy {
159 channel: String,
161 detail: String,
163 },
164
165 #[error(
168 "pending activity collision for workflow {workflow_id}, activity {activity_id}: \
169 a live responder already owns this execution site"
170 )]
171 PendingActivityCollision {
172 workflow_id: WorkflowId,
174 activity_id: ActivityId,
176 },
177
178 #[error(
181 "activity completion rejected for workflow {workflow_id}, activity {activity_id}: {reason}"
182 )]
183 ActivityCompletionRejected {
184 workflow_id: WorkflowId,
186 activity_id: ActivityId,
188 reason: CompletionRejectionReason,
190 },
191
192 #[error(
203 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
204 is already executing at this server"
205 )]
206 DeclaredAttemptCollision {
207 workflow_id: WorkflowId,
209 activity_id: ActivityId,
211 attempt: u32,
213 },
214
215 #[error("{resource} lock was poisoned")]
217 LockPoisoned {
218 resource: &'static str,
220 },
221
222 #[error("wire error: {wire}")]
224 Wire {
225 wire: WireError,
227 },
228}
229
230#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
232pub enum CompletionRejectionReason {
233 #[error("completion token is missing (worker registration era is incompatible)")]
235 MissingCompletionToken,
236 #[error("no execution generation is currently accepting completion")]
238 NoCurrentGeneration,
239 #[error("completion token belongs to a stale execution generation")]
241 StaleGeneration,
242}
243
244#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
246pub enum StreamFailure {
247 #[error("consumer lagged behind bounded buffer")]
249 Lagged,
250 #[error("subscriber connection closed")]
252 Closed,
253 #[error("engine event stream closed")]
255 UpstreamClosed,
256}
257
258impl From<WireError> for ServerError {
259 fn from(wire: WireError) -> Self {
260 Self::Wire { wire }
261 }
262}
263
264impl ServerError {
265 #[must_use]
268 pub fn to_wire_error(&self) -> WireError {
269 match self {
270 Self::Config { .. }
271 | Self::UnsafeDataRootAncestor { .. }
272 | Self::TransportBind { .. }
273 | Self::Transport { .. }
274 | Self::SignalListener { .. }
275 | Self::DeathNote { .. }
276 | Self::LockPoisoned { .. } => WireError::backend("server backend failure"),
277 Self::ActivityCompletionRejected { .. } => {
278 WireError::backend("stale activity completion rejected")
279 }
280 Self::PendingActivityCollision { .. } => {
281 WireError::backend("pending activity collision")
282 }
283 Self::DeclaredAttemptCollision { .. } => {
284 WireError::backend("declared command attempt collision")
285 }
286 Self::WorkerDispatch { .. } => WireError::backend("worker dispatch failed"),
287 Self::WorkerConnectionLost { .. } => {
288 WireError::backend("worker connection lost during dispatch")
289 }
290 Self::WorkerBusy { .. } => WireError::backend("worker connection busy during dispatch"),
291 Self::Namespace { message } => WireError::namespace_denied(message.clone()),
292 Self::EngineCall { source } => wire_from_engine(source),
293 Self::StoreBackend { source } => wire_from_store(source),
294 Self::Stream { failure } => match failure {
295 StreamFailure::Lagged => WireError::lagged("subscriber lagged behind"),
296 StreamFailure::Closed | StreamFailure::UpstreamClosed => {
297 WireError::backend("event stream closed")
298 }
299 },
300 Self::Wire { wire } => wire.clone(),
301 }
302 }
303
304 #[must_use]
306 pub const fn is_config(&self) -> bool {
307 matches!(
308 self,
309 Self::Config { .. } | Self::UnsafeDataRootAncestor { .. }
310 )
311 }
312
313 #[must_use]
315 pub fn namespace_denied(message: impl Into<String>) -> Self {
316 Self::Namespace {
317 message: message.into(),
318 }
319 }
320
321 #[must_use]
329 pub fn placement_admission_denied(
330 namespace: &str,
331 worker_node: Option<&str>,
332 required: &std::collections::BTreeSet<String>,
333 ) -> Self {
334 let node = worker_node.unwrap_or("none");
335 let required = required
336 .iter()
337 .map(String::as_str)
338 .collect::<Vec<_>>()
339 .join(", ");
340 Self::namespace_denied(format!(
341 "worker registration rejected: namespace {namespace} is Pinned to node label(s) \
342 [{required}] but the worker advertises node {node}, which is not in the required set"
343 ))
344 }
345
346 #[must_use]
349 pub fn deploy_denied(message: impl Into<String>) -> Self {
350 Self::Wire {
351 wire: WireError::deploy_denied(message),
352 }
353 }
354
355 #[must_use]
357 pub const fn lagged_stream() -> Self {
358 Self::Stream {
359 failure: StreamFailure::Lagged,
360 }
361 }
362
363 #[must_use]
365 pub fn worker_dispatch(
366 namespace: impl Into<String>,
367 activity_type: impl Into<String>,
368 reason: impl Into<String>,
369 ) -> Self {
370 Self::WorkerDispatch {
371 namespace: namespace.into(),
372 activity_type: activity_type.into(),
373 reason: reason.into(),
374 }
375 }
376
377 #[must_use]
380 pub fn worker_connection_lost(channel: impl Into<String>, detail: impl Into<String>) -> Self {
381 Self::WorkerConnectionLost {
382 channel: channel.into(),
383 detail: detail.into(),
384 }
385 }
386
387 #[must_use]
393 pub const fn is_worker_connection_lost(&self) -> bool {
394 matches!(self, Self::WorkerConnectionLost { .. })
395 }
396
397 #[must_use]
400 pub fn worker_busy(channel: impl Into<String>, detail: impl Into<String>) -> Self {
401 Self::WorkerBusy {
402 channel: channel.into(),
403 detail: detail.into(),
404 }
405 }
406
407 #[must_use]
414 pub const fn is_worker_busy(&self) -> bool {
415 matches!(self, Self::WorkerBusy { .. })
416 }
417
418 #[must_use]
420 pub const fn lock_poisoned(resource: &'static str) -> Self {
421 Self::LockPoisoned { resource }
422 }
423}
424
425#[derive(Clone)]
427pub struct ErrorTraceFields<'a> {
428 pub error_type: Cow<'a, str>,
430 pub store_error_type: Option<&'static str>,
432 pub reason: &'a dyn std::fmt::Display,
434}
435
436impl ServerError {
437 #[must_use]
439 pub fn trace_fields(&self) -> ErrorTraceFields<'_> {
440 match self {
441 Self::Config { message } => ErrorTraceFields {
442 error_type: Cow::Borrowed("Config"),
443 store_error_type: None,
444 reason: message,
445 },
446 Self::UnsafeDataRootAncestor { reason, .. } => ErrorTraceFields {
447 error_type: Cow::Borrowed("UnsafeDataRootAncestor"),
448 store_error_type: None,
449 reason,
450 },
451 Self::TransportBind { message, .. } => ErrorTraceFields {
452 error_type: Cow::Borrowed("TransportBind"),
453 store_error_type: None,
454 reason: message,
455 },
456 Self::Transport { message, .. } => ErrorTraceFields {
457 error_type: Cow::Borrowed("Transport"),
458 store_error_type: None,
459 reason: message,
460 },
461 Self::SignalListener { message, .. } => ErrorTraceFields {
462 error_type: Cow::Borrowed("SignalListener"),
463 store_error_type: None,
464 reason: message,
465 },
466 Self::DeathNote { message } => ErrorTraceFields {
467 error_type: Cow::Borrowed("DeathNote"),
468 store_error_type: None,
469 reason: message,
470 },
471 Self::Namespace { message } => ErrorTraceFields {
472 error_type: Cow::Borrowed("Namespace"),
473 store_error_type: None,
474 reason: message,
475 },
476 Self::EngineCall { source } => engine_trace_fields(source),
477 Self::StoreBackend { source } => store_trace_fields(source),
478 Self::Stream { failure } => ErrorTraceFields {
479 error_type: Cow::Borrowed("Stream"),
480 store_error_type: None,
481 reason: failure,
482 },
483 Self::WorkerDispatch { reason, .. } => ErrorTraceFields {
484 error_type: Cow::Borrowed("WorkerDispatch"),
485 store_error_type: None,
486 reason,
487 },
488 Self::WorkerConnectionLost { detail, .. } => ErrorTraceFields {
489 error_type: Cow::Borrowed("WorkerConnectionLost"),
490 store_error_type: None,
491 reason: detail,
492 },
493 Self::WorkerBusy { detail, .. } => ErrorTraceFields {
494 error_type: Cow::Borrowed("WorkerBusy"),
495 store_error_type: None,
496 reason: detail,
497 },
498 Self::PendingActivityCollision { activity_id, .. } => ErrorTraceFields {
499 error_type: Cow::Borrowed("PendingActivityCollision"),
500 store_error_type: None,
501 reason: activity_id,
502 },
503 Self::DeclaredAttemptCollision { activity_id, .. } => ErrorTraceFields {
504 error_type: Cow::Borrowed("DeclaredAttemptCollision"),
505 store_error_type: None,
506 reason: activity_id,
507 },
508 Self::ActivityCompletionRejected { reason, .. } => ErrorTraceFields {
509 error_type: Cow::Borrowed("ActivityCompletionRejected"),
510 store_error_type: None,
511 reason,
512 },
513 Self::LockPoisoned { resource } => ErrorTraceFields {
514 error_type: Cow::Borrowed("LockPoisoned"),
515 store_error_type: None,
516 reason: resource,
517 },
518 Self::Wire { wire } => ErrorTraceFields {
519 error_type: wire
520 .error_type
521 .as_deref()
522 .map_or_else(|| Cow::Borrowed(wire.code.as_str()), Cow::Borrowed),
523 store_error_type: None,
524 reason: wire,
525 },
526 }
527 }
528}
529
530fn never_alive_error_type(source: &EngineError) -> &'static str {
542 match source {
543 EngineError::TerminalWriterUnavailable { .. } => "TerminalWriterUnavailable",
544 EngineError::TerminalWriterHeld { .. } => "TerminalWriterHeld",
545 EngineError::RunIsRecoverable { .. } => "RunIsRecoverable",
546 EngineError::NoResidencyVerdict { .. } => "NoResidencyVerdict",
547 _ => "EngineError",
548 }
549}
550
551fn durability_trace_fields<'a>(
557 durability: &'a aion::durability::DurabilityError,
558 source: &'a EngineError,
559) -> ErrorTraceFields<'a> {
560 match durability {
561 aion::durability::DurabilityError::Store(store) => store_trace_fields(store),
562 aion::durability::DurabilityError::NonDeterminism(_)
563 | aion::durability::DurabilityError::HistoryShape { .. }
564 | aion::durability::DurabilityError::SearchAttribute(_) => {
565 simple_engine_fields("Durability", source)
566 }
567 aion::durability::DurabilityError::EngineTaskEpochClosed { .. } => {
573 simple_engine_fields("EngineTaskEpochClosed", source)
574 }
575 }
576}
577
578fn engine_trace_fields(source: &EngineError) -> ErrorTraceFields<'_> {
579 match source {
580 EngineError::WorkflowNotFound { .. } => simple_engine_fields("WorkflowNotFound", source),
581 EngineError::TerminalWriterUnavailable { .. }
583 | EngineError::TerminalWriterHeld { .. }
584 | EngineError::RunIsRecoverable { .. }
585 | EngineError::NoResidencyVerdict { .. } => {
586 simple_engine_fields(never_alive_error_type(source), source)
587 }
588 EngineError::InvalidState { .. } => simple_engine_fields("InvalidState", source),
589 EngineError::ScheduleNotFound { .. } => simple_engine_fields("ScheduleNotFound", source),
590 EngineError::ShuttingDown => simple_engine_fields("ShuttingDown", source),
591 EngineError::EngineTaskEpochClosed { .. } => {
592 simple_engine_fields("EngineTaskEpochClosed", source)
593 }
594 EngineError::Store(store) => store_trace_fields(store),
595 EngineError::Durability(durability) => durability_trace_fields(durability, source),
596 EngineError::MissingStore => simple_engine_fields("MissingStore", source),
597 EngineError::MissingVisibilityStore => {
598 simple_engine_fields("MissingVisibilityStore", source)
599 }
600 EngineError::ConflictingEventPublisher => {
601 simple_engine_fields("ConflictingEventPublisher", source)
602 }
603 EngineError::EventStreaming(_) => simple_engine_fields("EventStreaming", source),
604 EngineError::Load { .. } => simple_engine_fields("Load", source),
605 EngineError::UnenforceableContract { .. } => {
606 simple_engine_fields("UnenforceableContract", source)
607 }
608 EngineError::UnknownVersion { .. } => simple_engine_fields("UnknownVersion", source),
609 EngineError::VersionPinned { .. } => simple_engine_fields("VersionPinned", source),
610 EngineError::RouteActive { .. } => simple_engine_fields("RouteActive", source),
611 EngineError::ManifestMismatch { .. } => simple_engine_fields("ManifestMismatch", source),
612 EngineError::Package(_) => simple_engine_fields("Package", source),
613 EngineError::ContractIdentity { .. } => simple_engine_fields("ContractIdentity", source),
614 EngineError::NoQueueDeclaration { .. } => {
615 simple_engine_fields("NoQueueDeclaration", source)
616 }
617 EngineError::StartInputRefused { .. } => simple_engine_fields("StartInputRefused", source),
618 EngineError::SignalRefused { .. } => simple_engine_fields("SignalRefused", source),
619 EngineError::Schedule { .. } => simple_engine_fields("Schedule", source),
620 EngineError::Runtime { .. } => simple_engine_fields("Runtime", source),
621 EngineError::Gate3BifReplacementMissing { .. } => {
622 simple_engine_fields("Gate3BifReplacementMissing", source)
623 }
624 EngineError::StartupRecoveryNotDeferred => {
625 simple_engine_fields("StartupRecoveryNotDeferred", source)
626 }
627 EngineError::StartupRecoveryAlreadyRan => {
628 simple_engine_fields("StartupRecoveryAlreadyRan", source)
629 }
630 EngineError::StartupCatchupBeforeWorkflowRecovery => {
631 simple_engine_fields("StartupCatchupBeforeWorkflowRecovery", source)
632 }
633 EngineError::StartupRecoverySlotPoisoned => {
634 simple_engine_fields("StartupRecoverySlotPoisoned", source)
635 }
636 EngineError::CleanupExecutorPoisoned => {
637 simple_engine_fields("CleanupExecutorPoisoned", source)
638 }
639 EngineError::CleanupExecutorShutdownTimedOut { .. } => {
640 simple_engine_fields("CleanupExecutorShutdownTimedOut", source)
641 }
642 EngineError::RunNotInHistory { .. } => simple_engine_fields("RunNotInHistory", source),
643 EngineError::ProcessExitRegistryPoisoned => {
644 simple_engine_fields("ProcessExitRegistryPoisoned", source)
645 }
646 EngineError::ProcessExitOwnershipPoisoned { .. } => {
647 simple_engine_fields("ProcessExitOwnershipPoisoned", source)
648 }
649 EngineError::ProcessExitStatePoisoned { .. }
650 | EngineError::ProcessExitSubscriptionUnavailable
651 | EngineError::ProcessExitDrainerSpawn { .. }
652 | EngineError::ProcessExitDrainerPoisoned
653 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
654 | EngineError::ProcessExitEventStreamDisconnected
655 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
656 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_trace(source),
657 EngineError::ProcessExitCallbackDispatcherPoisoned
658 | EngineError::ProcessExitCallbackDispatcherUnavailable
659 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
660 process_exit::callback_trace(source)
661 }
662 EngineError::ProcessExitAlreadyTerminal { .. } => {
663 simple_engine_fields("ProcessExitAlreadyTerminal", source)
664 }
665 EngineError::ActivityDeliveryPoisoned { .. } => {
666 simple_engine_fields("ActivityDeliveryPoisoned", source)
667 }
668 EngineError::RegistryPoisoned => simple_engine_fields("RegistryPoisoned", source),
669 EngineError::CatalogPoisoned => simple_engine_fields("CatalogPoisoned", source),
670 EngineError::NifRegistration { .. } => simple_engine_fields("NifRegistration", source),
671 EngineError::SignalRouter(_) => simple_engine_fields("SignalRouter", source),
672 EngineError::Query(query) => simple_engine_fields(engine::query_error_type(query), source),
673 }
674}
675
676fn simple_engine_fields<'a>(
677 error_type: &'static str,
678 source: &'a EngineError,
679) -> ErrorTraceFields<'a> {
680 ErrorTraceFields {
681 error_type: Cow::Borrowed(error_type),
682 store_error_type: None,
683 reason: source,
684 }
685}
686
687fn store_trace_fields(source: &StoreError) -> ErrorTraceFields<'_> {
688 ErrorTraceFields {
689 error_type: Cow::Borrowed("StoreError"),
690 store_error_type: Some(engine::store_error_type(source)),
691 reason: source,
692 }
693}
694
695fn wire_from_engine(source: &EngineError) -> WireError {
696 use EngineError as E;
697 use engine::backend_wire as backend;
698
699 match source {
700 EngineError::WorkflowNotFound { .. } => {
701 WireError::not_found_with_type("WorkflowNotFound", source.to_string())
702 }
703 EngineError::InvalidState { reason } => engine::invalid_state_wire(reason),
705 E::TerminalWriterUnavailable { .. }
711 | E::TerminalWriterHeld { .. }
712 | E::RunIsRecoverable { .. }
713 | E::NoResidencyVerdict { .. } => engine::invalid_state_wire(&source.to_string())
714 .with_error_type(never_alive_error_type(source)),
715 EngineError::ScheduleNotFound { .. } => {
716 WireError::not_found_with_type("ScheduleNotFound", source.to_string())
717 }
718 EngineError::ShuttingDown => {
719 WireError::not_running_with_type("ShuttingDown", source.to_string())
720 }
721 E::EngineTaskEpochClosed { .. } => backend("EngineTaskEpochClosed", source),
742 EngineError::Store(store) => wire_from_store(store),
743 EngineError::Durability(durability) => engine::durability_wire(durability, source),
744 E::MissingStore => backend("MissingStore", source),
745 E::MissingVisibilityStore => backend("MissingVisibilityStore", source),
746 E::ConflictingEventPublisher => backend("ConflictingEventPublisher", source),
747 E::EventStreaming(_) => backend("EventStreaming", source),
748 E::Load { .. } => backend("Load", source),
749 EngineError::UnenforceableContract { .. } => {
752 WireError::invalid_input(source.to_string()).with_error_type("UnenforceableContract")
753 }
754 EngineError::UnknownVersion { .. } => {
756 WireError::not_found_with_type("UnknownVersion", source.to_string())
757 }
758 EngineError::VersionPinned { .. } => {
759 WireError::version_pinned(source.to_string()).with_error_type("VersionPinned")
760 }
761 EngineError::RouteActive { .. } => {
762 WireError::version_pinned(source.to_string()).with_error_type("RouteActive")
763 }
764 EngineError::ManifestMismatch { .. } => {
765 WireError::invalid_input(source.to_string()).with_error_type("ManifestMismatch")
766 }
767 E::Package(_) => backend("Package", source),
768 E::ContractIdentity { .. } => engine::contract_refusal_wire("ContractIdentity", source),
769 E::NoQueueDeclaration { .. } => engine::contract_refusal_wire("NoQueueDeclaration", source),
770 E::StartInputRefused { .. } => engine::declared_contract_wire("StartInputRefused", source),
771 E::SignalRefused { .. } => engine::declared_contract_wire("SignalRefused", source),
772 EngineError::Schedule { .. } => backend("Schedule", source),
773 E::Runtime { .. } => backend("Runtime", source),
774 E::Gate3BifReplacementMissing { .. } => backend("Gate3BifReplacementMissing", source),
775 E::StartupRecoveryNotDeferred => backend("StartupRecoveryNotDeferred", source),
778 E::StartupRecoveryAlreadyRan => backend("StartupRecoveryAlreadyRan", source),
779 E::StartupCatchupBeforeWorkflowRecovery => {
780 backend("StartupCatchupBeforeWorkflowRecovery", source)
781 }
782 E::StartupRecoverySlotPoisoned => backend("StartupRecoverySlotPoisoned", source),
783 E::CleanupExecutorPoisoned => backend("CleanupExecutorPoisoned", source),
784 E::CleanupExecutorShutdownTimedOut { .. } => {
785 backend("CleanupExecutorShutdownTimedOut", source)
786 }
787 E::RunNotInHistory { .. } => backend("RunNotInHistory", source),
793 E::ProcessExitRegistryPoisoned => backend("ProcessExitRegistryPoisoned", source),
794 E::ProcessExitOwnershipPoisoned { .. } => backend("ProcessExitOwnershipPoisoned", source),
795 EngineError::ProcessExitStatePoisoned { .. }
796 | EngineError::ProcessExitSubscriptionUnavailable
797 | EngineError::ProcessExitDrainerSpawn { .. }
798 | EngineError::ProcessExitDrainerPoisoned
799 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
800 | EngineError::ProcessExitEventStreamDisconnected
801 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
802 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_wire(source),
803 EngineError::ProcessExitCallbackDispatcherPoisoned
804 | EngineError::ProcessExitCallbackDispatcherUnavailable
805 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
806 process_exit::callback_wire(source)
807 }
808 E::ProcessExitAlreadyTerminal { .. } => backend("ProcessExitAlreadyTerminal", source),
809 E::ActivityDeliveryPoisoned { .. } => backend("ActivityDeliveryPoisoned", source),
810 E::CatalogPoisoned => backend("CatalogPoisoned", source),
811 E::RegistryPoisoned => backend("RegistryPoisoned", source),
812 E::NifRegistration { .. } => backend("NifRegistration", source),
813 E::SignalRouter(_) => backend("SignalRouter", source),
814 EngineError::Query(query) => engine::query_wire(query, source),
815 }
816}
817
818fn wire_from_store(source: &StoreError) -> WireError {
819 match source {
820 StoreError::SequenceConflict { .. } => WireError::new_with_type(
821 aion_proto::WireErrorCode::SequenceConflict,
822 "SequenceConflict",
823 source.to_string(),
824 ),
825 StoreError::NotFound { .. } => {
826 WireError::not_found_with_type("NotFound", source.to_string())
827 }
828 StoreError::NotOwner { .. } => {
829 WireError::not_owner(source.to_string()).with_error_type("NotOwner")
830 }
831 StoreError::Backend(_) => WireError::backend_with_type("Backend", source.to_string()),
832 StoreError::Serialization(_) => {
833 WireError::backend_with_type("Serialization", source.to_string())
834 }
835 }
836}
837
838#[cfg(test)]
839#[path = "error_tests.rs"]
840mod tests;