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(transparent)]
97 HomeAlreadyClaimed {
98 refusal: Box<crate::control::claim::HomeAlreadyClaimed>,
102 },
103
104 #[error("incarnation identity error: {message}")]
107 Incarnation {
108 message: String,
110 },
111
112 #[error("namespace error: {message}")]
114 Namespace {
115 message: String,
117 },
118
119 #[error("engine call failed: {source}")]
121 EngineCall {
122 #[from]
124 source: EngineError,
125 },
126
127 #[error("store backend failed: {source}")]
129 StoreBackend {
130 #[from]
132 source: StoreError,
133 },
134
135 #[error("stream failure: {failure}")]
137 Stream {
138 failure: StreamFailure,
140 },
141
142 #[error(
144 "worker dispatch failed for namespace {namespace}, activity type {activity_type}: {reason}"
145 )]
146 WorkerDispatch {
147 namespace: String,
149 activity_type: String,
151 reason: String,
153 },
154
155 #[error("worker connection lost during dispatch on {channel}: {detail}")]
168 WorkerConnectionLost {
169 channel: String,
171 detail: String,
173 },
174
175 #[error("worker connection busy during dispatch on {channel}: {detail}")]
186 WorkerBusy {
187 channel: String,
189 detail: String,
191 },
192
193 #[error(
204 "pending activity collision for workflow {workflow_id}, activity {activity_id}: \
205 attempt {incoming_attempt} arrived while attempt {held_attempt} still holds this \
206 execution site, and does not supersede it"
207 )]
208 PendingActivityCollision {
209 workflow_id: WorkflowId,
211 activity_id: ActivityId,
213 held_attempt: u32,
215 incoming_attempt: u32,
217 },
218
219 #[error(
222 "activity completion rejected for workflow {workflow_id}, activity {activity_id}: {reason}"
223 )]
224 ActivityCompletionRejected {
225 workflow_id: WorkflowId,
227 activity_id: ActivityId,
229 reason: CompletionRejectionReason,
231 },
232
233 #[error(
244 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
245 is already executing at this server"
246 )]
247 DeclaredAttemptCollision {
248 workflow_id: WorkflowId,
250 activity_id: ActivityId,
252 attempt: u32,
254 },
255
256 #[error(
266 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
267 refused: this server is draining and starts no new work"
268 )]
269 DrainingRefusedDeclaredAttempt {
270 workflow_id: WorkflowId,
272 activity_id: ActivityId,
274 attempt: u32,
276 },
277
278 #[error("{resource} lock was poisoned")]
280 LockPoisoned {
281 resource: &'static str,
283 },
284
285 #[error("wire error: {wire}")]
287 Wire {
288 wire: WireError,
290 },
291}
292
293#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
295pub enum CompletionRejectionReason {
296 #[error("completion token is missing (worker registration era is incompatible)")]
298 MissingCompletionToken,
299 #[error("no execution generation is currently accepting completion")]
301 NoCurrentGeneration,
302 #[error("completion token belongs to a stale execution generation")]
304 StaleGeneration,
305}
306
307#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
309pub enum StreamFailure {
310 #[error("consumer lagged behind bounded buffer")]
312 Lagged,
313 #[error("subscriber connection closed")]
315 Closed,
316 #[error("engine event stream closed")]
318 UpstreamClosed,
319}
320
321impl From<WireError> for ServerError {
322 fn from(wire: WireError) -> Self {
323 Self::Wire { wire }
324 }
325}
326
327impl ServerError {
328 #[must_use]
331 pub fn to_wire_error(&self) -> WireError {
332 match self {
333 Self::Config { .. }
334 | Self::UnsafeDataRootAncestor { .. }
335 | Self::TransportBind { .. }
336 | Self::Transport { .. }
337 | Self::SignalListener { .. }
338 | Self::DeathNote { .. }
339 | Self::PidFile { .. }
340 | Self::HomeAlreadyClaimed { .. }
341 | Self::Incarnation { .. }
342 | Self::LockPoisoned { .. } => WireError::backend("server backend failure"),
343 Self::ActivityCompletionRejected { .. } => {
344 WireError::backend("stale activity completion rejected")
345 }
346 Self::PendingActivityCollision { .. } => {
347 WireError::backend("pending activity collision")
348 }
349 Self::DeclaredAttemptCollision { .. } => {
350 WireError::backend("declared command attempt collision")
351 }
352 Self::DrainingRefusedDeclaredAttempt { .. } => {
353 WireError::backend("declared command refused: server draining")
354 }
355 Self::WorkerDispatch { .. } => WireError::backend("worker dispatch failed"),
356 Self::WorkerConnectionLost { .. } => {
357 WireError::backend("worker connection lost during dispatch")
358 }
359 Self::WorkerBusy { .. } => WireError::backend("worker connection busy during dispatch"),
360 Self::Namespace { message } => WireError::namespace_denied(message.clone()),
361 Self::EngineCall { source } => wire_from_engine(source),
362 Self::StoreBackend { source } => wire_from_store(source),
363 Self::Stream { failure } => match failure {
364 StreamFailure::Lagged => WireError::lagged("subscriber lagged behind"),
365 StreamFailure::Closed | StreamFailure::UpstreamClosed => {
366 WireError::backend("event stream closed")
367 }
368 },
369 Self::Wire { wire } => wire.clone(),
370 }
371 }
372
373 #[must_use]
375 pub const fn is_config(&self) -> bool {
376 matches!(
382 self,
383 Self::Config { .. }
384 | Self::UnsafeDataRootAncestor { .. }
385 | Self::HomeAlreadyClaimed { .. }
386 )
387 }
388
389 #[must_use]
391 pub fn namespace_denied(message: impl Into<String>) -> Self {
392 Self::Namespace {
393 message: message.into(),
394 }
395 }
396
397 #[must_use]
405 pub fn placement_admission_denied(
406 namespace: &str,
407 worker_node: Option<&str>,
408 required: &std::collections::BTreeSet<String>,
409 ) -> Self {
410 let node = worker_node.unwrap_or("none");
411 let required = required
412 .iter()
413 .map(String::as_str)
414 .collect::<Vec<_>>()
415 .join(", ");
416 Self::namespace_denied(format!(
417 "worker registration rejected: namespace {namespace} is Pinned to node label(s) \
418 [{required}] but the worker advertises node {node}, which is not in the required set"
419 ))
420 }
421
422 #[must_use]
425 pub fn deploy_denied(message: impl Into<String>) -> Self {
426 Self::Wire {
427 wire: WireError::deploy_denied(message),
428 }
429 }
430
431 #[must_use]
441 pub fn grant_denied(message: impl Into<String>) -> Self {
442 Self::Wire {
443 wire: WireError::grant_denied(message),
444 }
445 }
446
447 #[must_use]
449 pub const fn lagged_stream() -> Self {
450 Self::Stream {
451 failure: StreamFailure::Lagged,
452 }
453 }
454
455 #[must_use]
457 pub fn worker_dispatch(
458 namespace: impl Into<String>,
459 activity_type: impl Into<String>,
460 reason: impl Into<String>,
461 ) -> Self {
462 Self::WorkerDispatch {
463 namespace: namespace.into(),
464 activity_type: activity_type.into(),
465 reason: reason.into(),
466 }
467 }
468
469 #[must_use]
472 pub fn worker_connection_lost(channel: impl Into<String>, detail: impl Into<String>) -> Self {
473 Self::WorkerConnectionLost {
474 channel: channel.into(),
475 detail: detail.into(),
476 }
477 }
478
479 #[must_use]
485 pub const fn is_worker_connection_lost(&self) -> bool {
486 matches!(self, Self::WorkerConnectionLost { .. })
487 }
488
489 #[must_use]
492 pub fn worker_busy(channel: impl Into<String>, detail: impl Into<String>) -> Self {
493 Self::WorkerBusy {
494 channel: channel.into(),
495 detail: detail.into(),
496 }
497 }
498
499 #[must_use]
506 pub const fn is_worker_busy(&self) -> bool {
507 matches!(self, Self::WorkerBusy { .. })
508 }
509
510 #[must_use]
512 pub const fn lock_poisoned(resource: &'static str) -> Self {
513 Self::LockPoisoned { resource }
514 }
515}
516
517#[derive(Clone)]
519pub struct ErrorTraceFields<'a> {
520 pub error_type: Cow<'a, str>,
522 pub store_error_type: Option<&'static str>,
524 pub reason: &'a dyn std::fmt::Display,
526}
527
528impl<'a> ErrorTraceFields<'a> {
529 fn plain(error_type: &'static str, reason: &'a dyn std::fmt::Display) -> Self {
531 Self {
532 error_type: Cow::Borrowed(error_type),
533 store_error_type: None,
534 reason,
535 }
536 }
537}
538
539impl ServerError {
540 #[must_use]
542 pub fn trace_fields(&self) -> ErrorTraceFields<'_> {
543 match self {
544 Self::Config { message } => ErrorTraceFields::plain("Config", message),
545 Self::UnsafeDataRootAncestor { reason, .. } => {
546 ErrorTraceFields::plain("UnsafeDataRootAncestor", reason)
547 }
548 Self::TransportBind { message, .. } => {
549 ErrorTraceFields::plain("TransportBind", message)
550 }
551 Self::Transport { message, .. } => ErrorTraceFields::plain("Transport", message),
552 Self::SignalListener { message, .. } => {
553 ErrorTraceFields::plain("SignalListener", message)
554 }
555 Self::PidFile { message } => ErrorTraceFields::plain("PidFile", message),
556 Self::HomeAlreadyClaimed { refusal } => {
557 ErrorTraceFields::plain("HomeAlreadyClaimed", refusal.as_ref())
558 }
559 Self::Incarnation { message } => ErrorTraceFields::plain("Incarnation", message),
560 Self::DeathNote { message } => ErrorTraceFields::plain("DeathNote", message),
561 Self::Namespace { message } => ErrorTraceFields::plain("Namespace", message),
562 Self::EngineCall { source } => engine_trace_fields(source),
563 Self::StoreBackend { source } => store_trace_fields(source),
564 Self::Stream { failure } => ErrorTraceFields::plain("Stream", failure),
565 Self::WorkerDispatch { reason, .. } => {
566 ErrorTraceFields::plain("WorkerDispatch", reason)
567 }
568 Self::WorkerConnectionLost { detail, .. } => {
569 ErrorTraceFields::plain("WorkerConnectionLost", detail)
570 }
571 Self::WorkerBusy { detail, .. } => ErrorTraceFields::plain("WorkerBusy", detail),
572 Self::PendingActivityCollision { activity_id, .. } => {
573 ErrorTraceFields::plain("PendingActivityCollision", activity_id)
574 }
575 Self::DeclaredAttemptCollision { activity_id, .. } => {
576 ErrorTraceFields::plain("DeclaredAttemptCollision", activity_id)
577 }
578 Self::DrainingRefusedDeclaredAttempt { activity_id, .. } => {
579 ErrorTraceFields::plain("DrainingRefusedDeclaredAttempt", activity_id)
580 }
581 Self::ActivityCompletionRejected { reason, .. } => {
582 ErrorTraceFields::plain("ActivityCompletionRejected", reason)
583 }
584 Self::LockPoisoned { resource } => ErrorTraceFields::plain("LockPoisoned", resource),
585 Self::Wire { wire } => ErrorTraceFields {
586 error_type: wire
587 .error_type
588 .as_deref()
589 .map_or_else(|| Cow::Borrowed(wire.code.as_str()), Cow::Borrowed),
590 store_error_type: None,
591 reason: wire,
592 },
593 }
594 }
595}
596
597fn never_alive_error_type(source: &EngineError) -> &'static str {
609 match source {
610 EngineError::TerminalWriterUnavailable { .. } => "TerminalWriterUnavailable",
611 EngineError::TerminalWriterHeld { .. } => "TerminalWriterHeld",
612 EngineError::WorkflowWriterHeld { .. } => "WorkflowWriterHeld",
613 EngineError::RunIsRecoverable { .. } => "RunIsRecoverable",
614 EngineError::NoResidencyVerdict { .. } => "NoResidencyVerdict",
615 _ => "EngineError",
616 }
617}
618
619fn durability_trace_fields<'a>(
625 durability: &'a aion::durability::DurabilityError,
626 source: &'a EngineError,
627) -> ErrorTraceFields<'a> {
628 match durability {
629 aion::durability::DurabilityError::Store(store) => store_trace_fields(store),
630 aion::durability::DurabilityError::NonDeterminism(_)
631 | aion::durability::DurabilityError::HistoryShape { .. }
632 | aion::durability::DurabilityError::SearchAttribute(_) => {
633 simple_engine_fields("Durability", source)
634 }
635 aion::durability::DurabilityError::EngineTaskEpochClosed { .. } => {
641 simple_engine_fields("EngineTaskEpochClosed", source)
642 }
643 }
644}
645
646fn engine_trace_fields(source: &EngineError) -> ErrorTraceFields<'_> {
647 match source {
648 EngineError::WorkflowNotFound { .. } => simple_engine_fields("WorkflowNotFound", source),
649 EngineError::TerminalWriterUnavailable { .. }
651 | EngineError::TerminalWriterHeld { .. }
652 | EngineError::WorkflowWriterHeld { .. }
655 | EngineError::RunIsRecoverable { .. }
656 | EngineError::NoResidencyVerdict { .. } => {
657 simple_engine_fields(never_alive_error_type(source), source)
658 }
659 EngineError::InvalidState { .. } => simple_engine_fields("InvalidState", source),
660 EngineError::ScheduleNotFound { .. } => simple_engine_fields("ScheduleNotFound", source),
661 EngineError::ShuttingDown => simple_engine_fields("ShuttingDown", source),
662 EngineError::EngineTaskEpochClosed { .. } => {
663 simple_engine_fields("EngineTaskEpochClosed", source)
664 }
665 EngineError::Store(store) => store_trace_fields(store),
666 EngineError::Durability(durability) => durability_trace_fields(durability, source),
667 EngineError::MissingStore
668 | EngineError::MissingVisibilityStore
669 | EngineError::MissingStopDrainTimeout
670 | EngineError::ZeroStopDrainTimeout
671 | EngineError::ConflictingEventPublisher => builder_trace_fields(source),
672 EngineError::EventStreaming(_) => simple_engine_fields("EventStreaming", source),
673 EngineError::Load { .. } => simple_engine_fields("Load", source),
674 EngineError::UnenforceableContract { .. } => {
675 simple_engine_fields("UnenforceableContract", source)
676 }
677 EngineError::UnknownVersion { .. } => simple_engine_fields("UnknownVersion", source),
678 EngineError::VersionPinned { .. } => simple_engine_fields("VersionPinned", source),
679 EngineError::RouteActive { .. } => simple_engine_fields("RouteActive", source),
680 EngineError::ManifestMismatch { .. } => simple_engine_fields("ManifestMismatch", source),
681 EngineError::Package(_) => simple_engine_fields("Package", source),
682 EngineError::ContractIdentity { .. } => simple_engine_fields("ContractIdentity", source),
683 EngineError::NoQueueDeclaration { .. } => {
684 simple_engine_fields("NoQueueDeclaration", source)
685 }
686 EngineError::StartInputRefused { .. } => simple_engine_fields("StartInputRefused", source),
687 EngineError::SignalRefused { .. } => simple_engine_fields("SignalRefused", source),
688 EngineError::ActivityLeaseAfterTerminal { .. } => {
689 simple_engine_fields("ActivityLeaseAfterTerminal", source)
690 }
691 EngineError::Schedule { .. } => simple_engine_fields("Schedule", source),
692 EngineError::Runtime { .. } => simple_engine_fields("Runtime", source),
693 EngineError::Gate3BifReplacementMissing { .. } => {
694 simple_engine_fields("Gate3BifReplacementMissing", source)
695 }
696 EngineError::StartupRecoveryNotDeferred => {
697 simple_engine_fields("StartupRecoveryNotDeferred", source)
698 }
699 EngineError::StartupRecoveryAlreadyRan => {
700 simple_engine_fields("StartupRecoveryAlreadyRan", source)
701 }
702 EngineError::StartupCatchupBeforeWorkflowRecovery => {
703 simple_engine_fields("StartupCatchupBeforeWorkflowRecovery", source)
704 }
705 EngineError::StartupRecoverySlotPoisoned => {
706 simple_engine_fields("StartupRecoverySlotPoisoned", source)
707 }
708 EngineError::CleanupExecutorPoisoned => {
709 simple_engine_fields("CleanupExecutorPoisoned", source)
710 }
711 EngineError::CleanupExecutorShutdownTimedOut { .. } => {
712 simple_engine_fields("CleanupExecutorShutdownTimedOut", source)
713 }
714 EngineError::RunNotInHistory { .. } => simple_engine_fields("RunNotInHistory", source),
715 EngineError::ProcessExitRegistryPoisoned => {
716 simple_engine_fields("ProcessExitRegistryPoisoned", source)
717 }
718 EngineError::ProcessExitOwnershipPoisoned { .. } => {
719 simple_engine_fields("ProcessExitOwnershipPoisoned", source)
720 }
721 EngineError::ProcessExitStatePoisoned { .. }
722 | EngineError::ProcessExitSubscriptionUnavailable
723 | EngineError::ProcessExitDrainerSpawn { .. }
724 | EngineError::ProcessExitDrainerPoisoned
725 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
726 | EngineError::ProcessExitEventStreamDisconnected
727 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
728 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_trace(source),
729 EngineError::ProcessExitCallbackDispatcherPoisoned
730 | EngineError::ProcessExitCallbackDispatcherUnavailable
731 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
732 process_exit::callback_trace(source)
733 }
734 EngineError::ProcessExitAlreadyTerminal { .. } => {
735 simple_engine_fields("ProcessExitAlreadyTerminal", source)
736 }
737 EngineError::ActivityDeliveryPoisoned { .. } => {
738 simple_engine_fields("ActivityDeliveryPoisoned", source)
739 }
740 EngineError::RegistryPoisoned => simple_engine_fields("RegistryPoisoned", source),
741 EngineError::CatalogPoisoned => simple_engine_fields("CatalogPoisoned", source),
742 EngineError::NifRegistration { .. } => simple_engine_fields("NifRegistration", source),
743 EngineError::SignalRouter(_) => simple_engine_fields("SignalRouter", source),
744 EngineError::Query(query) => simple_engine_fields(engine::query_error_type(query), source),
745 }
746}
747
748fn builder_trace_fields(source: &EngineError) -> ErrorTraceFields<'_> {
751 match source {
752 EngineError::MissingStore => simple_engine_fields("MissingStore", source),
753 EngineError::MissingVisibilityStore => {
754 simple_engine_fields("MissingVisibilityStore", source)
755 }
756 EngineError::MissingStopDrainTimeout => {
757 simple_engine_fields("MissingStopDrainTimeout", source)
758 }
759 EngineError::ZeroStopDrainTimeout => simple_engine_fields("ZeroStopDrainTimeout", source),
760 EngineError::ConflictingEventPublisher => {
761 simple_engine_fields("ConflictingEventPublisher", source)
762 }
763 _ => simple_engine_fields("EngineBuilder", source),
764 }
765}
766
767fn simple_engine_fields<'a>(
768 error_type: &'static str,
769 source: &'a EngineError,
770) -> ErrorTraceFields<'a> {
771 ErrorTraceFields {
772 error_type: Cow::Borrowed(error_type),
773 store_error_type: None,
774 reason: source,
775 }
776}
777
778fn store_trace_fields(source: &StoreError) -> ErrorTraceFields<'_> {
779 ErrorTraceFields {
780 error_type: Cow::Borrowed("StoreError"),
781 store_error_type: Some(engine::store_error_type(source)),
782 reason: source,
783 }
784}
785
786fn wire_from_engine(source: &EngineError) -> WireError {
787 use EngineError as E;
788 use engine::backend_wire as backend;
789
790 match source {
791 EngineError::WorkflowNotFound { .. } => {
792 WireError::not_found_with_type("WorkflowNotFound", source.to_string())
793 }
794 EngineError::InvalidState { reason } => engine::invalid_state_wire(reason),
796 E::TerminalWriterUnavailable { .. }
802 | E::TerminalWriterHeld { .. }
803 | E::WorkflowWriterHeld { .. }
807 | E::RunIsRecoverable { .. }
808 | E::NoResidencyVerdict { .. } => engine::invalid_state_wire(&source.to_string())
809 .with_error_type(never_alive_error_type(source)),
810 EngineError::ScheduleNotFound { .. } => {
811 WireError::not_found_with_type("ScheduleNotFound", source.to_string())
812 }
813 EngineError::ShuttingDown => {
814 WireError::not_running_with_type("ShuttingDown", source.to_string())
815 }
816 E::EngineTaskEpochClosed { .. } => backend("EngineTaskEpochClosed", source),
837 E::ActivityLeaseAfterTerminal { .. } => engine::invalid_state_wire(&source.to_string())
843 .with_error_type("ActivityLeaseAfterTerminal"),
844 EngineError::Store(store) => wire_from_store(store),
845 EngineError::Durability(durability) => engine::durability_wire(durability, source),
846 E::MissingStore => backend("MissingStore", source),
847 E::MissingVisibilityStore => backend("MissingVisibilityStore", source),
848 E::MissingStopDrainTimeout => backend("MissingStopDrainTimeout", source),
849 E::ZeroStopDrainTimeout => backend("ZeroStopDrainTimeout", source),
850 E::ConflictingEventPublisher => backend("ConflictingEventPublisher", source),
851 E::EventStreaming(_) => backend("EventStreaming", source),
852 E::Load { .. } => backend("Load", source),
853 EngineError::UnenforceableContract { .. } => {
856 WireError::invalid_input(source.to_string()).with_error_type("UnenforceableContract")
857 }
858 EngineError::UnknownVersion { .. } => {
860 WireError::not_found_with_type("UnknownVersion", source.to_string())
861 }
862 EngineError::VersionPinned { .. } => {
863 WireError::version_pinned(source.to_string()).with_error_type("VersionPinned")
864 }
865 EngineError::RouteActive { .. } => {
866 WireError::version_pinned(source.to_string()).with_error_type("RouteActive")
867 }
868 EngineError::ManifestMismatch { .. } => {
869 WireError::invalid_input(source.to_string()).with_error_type("ManifestMismatch")
870 }
871 E::Package(_) => backend("Package", source),
872 E::ContractIdentity { .. } => engine::contract_refusal_wire("ContractIdentity", source),
873 E::NoQueueDeclaration { .. } => engine::contract_refusal_wire("NoQueueDeclaration", source),
874 E::StartInputRefused { .. } => engine::declared_contract_wire("StartInputRefused", source),
875 E::SignalRefused { .. } => engine::declared_contract_wire("SignalRefused", source),
876 EngineError::Schedule { .. } => backend("Schedule", source),
877 E::Runtime { .. } => backend("Runtime", source),
878 E::Gate3BifReplacementMissing { .. } => backend("Gate3BifReplacementMissing", source),
879 E::StartupRecoveryNotDeferred => backend("StartupRecoveryNotDeferred", source),
882 E::StartupRecoveryAlreadyRan => backend("StartupRecoveryAlreadyRan", source),
883 E::StartupCatchupBeforeWorkflowRecovery => {
884 backend("StartupCatchupBeforeWorkflowRecovery", source)
885 }
886 E::StartupRecoverySlotPoisoned => backend("StartupRecoverySlotPoisoned", source),
887 E::CleanupExecutorPoisoned => backend("CleanupExecutorPoisoned", source),
888 E::CleanupExecutorShutdownTimedOut { .. } => {
889 backend("CleanupExecutorShutdownTimedOut", source)
890 }
891 E::RunNotInHistory { .. } => backend("RunNotInHistory", source),
897 E::ProcessExitRegistryPoisoned => backend("ProcessExitRegistryPoisoned", source),
898 E::ProcessExitOwnershipPoisoned { .. } => backend("ProcessExitOwnershipPoisoned", source),
899 EngineError::ProcessExitStatePoisoned { .. }
900 | EngineError::ProcessExitSubscriptionUnavailable
901 | EngineError::ProcessExitDrainerSpawn { .. }
902 | EngineError::ProcessExitDrainerPoisoned
903 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
904 | EngineError::ProcessExitEventStreamDisconnected
905 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
906 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_wire(source),
907 EngineError::ProcessExitCallbackDispatcherPoisoned
908 | EngineError::ProcessExitCallbackDispatcherUnavailable
909 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
910 process_exit::callback_wire(source)
911 }
912 E::ProcessExitAlreadyTerminal { .. } => backend("ProcessExitAlreadyTerminal", source),
913 E::ActivityDeliveryPoisoned { .. } => backend("ActivityDeliveryPoisoned", source),
914 E::CatalogPoisoned => backend("CatalogPoisoned", source),
915 E::RegistryPoisoned => backend("RegistryPoisoned", source),
916 E::NifRegistration { .. } => backend("NifRegistration", source),
917 E::SignalRouter(_) => backend("SignalRouter", source),
918 EngineError::Query(query) => engine::query_wire(query, source),
919 }
920}
921
922fn wire_from_store(source: &StoreError) -> WireError {
923 match source {
924 StoreError::SequenceConflict { .. } => WireError::new_with_type(
925 aion_proto::WireErrorCode::SequenceConflict,
926 "SequenceConflict",
927 source.to_string(),
928 ),
929 StoreError::NotFound { .. } => {
930 WireError::not_found_with_type("NotFound", source.to_string())
931 }
932 StoreError::AssistantSessionNotFound { .. } => {
936 WireError::not_found_with_type("AssistantSessionNotFound", source.to_string())
937 }
938 StoreError::NotOwner { .. } => {
939 WireError::not_owner(source.to_string()).with_error_type("NotOwner")
940 }
941 StoreError::Backend(_) => WireError::backend_with_type("Backend", source.to_string()),
942 StoreError::Serialization(_) => {
943 WireError::backend_with_type("Serialization", source.to_string())
944 }
945 StoreError::InvalidQuery(_) => {
949 WireError::invalid_input(source.to_string()).with_error_type("InvalidQuery")
950 }
951 }
952}
953
954#[cfg(test)]
955#[path = "error_tests.rs"]
956mod tests;