Skip to main content

canwu_sim/runtime/
error.rs

1use super::EntityRef;
2use serde::{Deserialize, Serialize};
3use std::error::Error;
4use std::fmt::{Display, Formatter};
5
6#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
7#[serde(rename_all = "snake_case")]
8pub enum ErrorCode {
9    ActorNotFound,
10    ArchiveNotReady,
11    ArmyNotFound,
12    DestinationNotFound,
13    DuplicateBoundaryWriter,
14    DuplicateDomainRecord,
15    DuplicateDomainRecordKind,
16    DuplicatePlugin,
17    DuplicatePluginCommand,
18    DuplicatePluginIngress,
19    DuplicatePluginSystem,
20    DuplicateStateOwner,
21    DuplicateReservationOfferer,
22    EntityNotFound,
23    DomainRecordNotFound,
24    DomainRecordReferenced,
25    DomainRecordVersionConflict,
26    InvalidAuthority,
27    InvalidArchive,
28    InvalidBoundary,
29    InvalidDecision,
30    InvalidDuration,
31    InvalidDomainRecord,
32    InvalidKnowledgeHolder,
33    InvalidKnowledgeRecord,
34    InvalidKnowledgeSchema,
35    InvalidKnowledgeAuthority,
36    KnowledgeLimitExceeded,
37    KnowledgeReadCutUnavailable,
38    KnowledgeRecordNotFound,
39    UndeclaredKnowledgeWrite,
40    EvidenceUnavailable,
41    EvidenceContentUnavailable,
42    DuplicateKnowledgeRecordKind,
43    InvalidRandomOperationEvidence,
44    RandomOperationConflict,
45    IdempotencyConflict,
46    InteractionReadOnly,
47    InvalidPayload,
48    InvalidPluginRegistration,
49    InvalidRandomDraw,
50    InvalidRandomStream,
51    InvalidRunConfiguration,
52    InvalidRunManifest,
53    InvalidSnapshot,
54    IdentifierExhausted,
55    LegacyReplayUnavailable,
56    LateIngress,
57    MissingIdempotencyKey,
58    MixedCommandIngress,
59    NoRoute,
60    PluginCommandNotFound,
61    PluginManifestMismatch,
62    PluginNotActive,
63    PluginPanicked,
64    PluginRegistrationClosed,
65    QueryBudgetExceeded,
66    ReplayMismatch,
67    ReplayEnvironmentMismatch,
68    SimulationRevisionConflict,
69    SimulationTimeConflict,
70    StaleSealToken,
71    StatePageUnavailable,
72    SynchronousReactionLimit,
73    UndeclaredRandomStream,
74    UndeclaredStateRead,
75    UndeclaredStateWrite,
76    UnsupportedSnapshotVersion,
77    UnsupportedRandomDrawAddress,
78    ValueOutOfRange,
79    /// A command or decision issuer resolves to a person who is not alive or
80    /// is detained or captive.
81    IssuerUnavailable,
82    /// A decision maker resolves to a person who is not alive or is detained
83    /// or captive.
84    DecisionMakerUnavailable,
85    /// Boundary proposals exceed the run's rule-evaluation trace limits.
86    EvaluationTraceLimitExceeded,
87    /// A transition manifest ready at the boundary was staged by some, but
88    /// not all, of its listed participants. The message names the manifest
89    /// and the missing participant plugins; the whole boundary rolled back.
90    ///
91    /// A retry of the same boundary with the same inputs fails the same way.
92    /// A ready boundary in which no participant stages, for example one
93    /// settled with a cadence under which no participant system runs,
94    /// expires the manifest instead; the coordinator may then register a new
95    /// attempt.
96    TransitionParticipantMissing,
97    /// A transition manifest's `expected_pre` or `expected_post` version
98    /// differs from the version the boundary holds or produces. The message
99    /// names the manifest and each mismatched record, which are also listed
100    /// in `related_entities`; the whole boundary rolled back. Recovery is the
101    /// same as for [`Self::TransitionParticipantMissing`].
102    TransitionVersionMismatch,
103}
104
105#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
106pub struct CanwuError {
107    pub code: ErrorCode,
108    pub message: String,
109    pub related_entities: Vec<EntityRef>,
110}
111
112impl CanwuError {
113    #[must_use]
114    pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
115        Self {
116            code,
117            message: message.into(),
118            related_entities: Vec::new(),
119        }
120    }
121
122    #[must_use]
123    pub fn with_entity(mut self, entity: EntityRef) -> Self {
124        self.related_entities.push(entity);
125        self
126    }
127}
128
129impl Display for CanwuError {
130    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
131        write!(
132            formatter,
133            "{}: {}",
134            error_code_name(&self.code),
135            self.message
136        )
137    }
138}
139
140impl Error for CanwuError {}
141
142const fn error_code_name(code: &ErrorCode) -> &'static str {
143    match code {
144        ErrorCode::ActorNotFound => "actor_not_found",
145        ErrorCode::ArchiveNotReady => "archive_not_ready",
146        ErrorCode::ArmyNotFound => "army_not_found",
147        ErrorCode::DestinationNotFound => "destination_not_found",
148        ErrorCode::DuplicateBoundaryWriter => "duplicate_boundary_writer",
149        ErrorCode::DuplicateDomainRecord => "duplicate_domain_record",
150        ErrorCode::DuplicateDomainRecordKind => "duplicate_domain_record_kind",
151        ErrorCode::DuplicatePlugin => "duplicate_plugin",
152        ErrorCode::DuplicatePluginCommand => "duplicate_plugin_command",
153        ErrorCode::DuplicatePluginIngress => "duplicate_plugin_ingress",
154        ErrorCode::DuplicatePluginSystem => "duplicate_plugin_system",
155        ErrorCode::DuplicateStateOwner => "duplicate_state_owner",
156        ErrorCode::DuplicateReservationOfferer => "duplicate_reservation_offerer",
157        ErrorCode::EntityNotFound => "entity_not_found",
158        ErrorCode::DomainRecordNotFound => "domain_record_not_found",
159        ErrorCode::DomainRecordReferenced => "domain_record_referenced",
160        ErrorCode::DomainRecordVersionConflict => "domain_record_version_conflict",
161        ErrorCode::InvalidAuthority => "invalid_authority",
162        ErrorCode::InvalidArchive => "invalid_archive",
163        ErrorCode::InvalidBoundary => "invalid_boundary",
164        ErrorCode::InvalidDecision => "invalid_decision",
165        ErrorCode::InvalidDuration => "invalid_duration",
166        ErrorCode::InvalidDomainRecord => "invalid_domain_record",
167        ErrorCode::InvalidKnowledgeHolder => "invalid_knowledge_holder",
168        ErrorCode::InvalidKnowledgeRecord => "invalid_knowledge_record",
169        ErrorCode::InvalidKnowledgeSchema => "invalid_knowledge_schema",
170        ErrorCode::InvalidKnowledgeAuthority => "invalid_knowledge_authority",
171        ErrorCode::KnowledgeLimitExceeded => "knowledge_limit_exceeded",
172        ErrorCode::KnowledgeReadCutUnavailable => "knowledge_read_cut_unavailable",
173        ErrorCode::KnowledgeRecordNotFound => "knowledge_record_not_found",
174        ErrorCode::UndeclaredKnowledgeWrite => "undeclared_knowledge_write",
175        ErrorCode::EvidenceUnavailable => "evidence_unavailable",
176        ErrorCode::EvidenceContentUnavailable => "evidence_content_unavailable",
177        ErrorCode::DuplicateKnowledgeRecordKind => "duplicate_knowledge_record_kind",
178        ErrorCode::InvalidRandomOperationEvidence => "invalid_random_operation_evidence",
179        ErrorCode::RandomOperationConflict => "random_operation_conflict",
180        ErrorCode::IdempotencyConflict => "idempotency_conflict",
181        ErrorCode::InteractionReadOnly => "interaction_read_only",
182        ErrorCode::InvalidPayload => "invalid_payload",
183        ErrorCode::InvalidPluginRegistration => "invalid_plugin_registration",
184        ErrorCode::InvalidRandomDraw => "invalid_random_draw",
185        ErrorCode::InvalidRandomStream => "invalid_random_stream",
186        ErrorCode::InvalidRunConfiguration => "invalid_run_configuration",
187        ErrorCode::InvalidRunManifest => "invalid_run_manifest",
188        ErrorCode::InvalidSnapshot => "invalid_snapshot",
189        ErrorCode::IdentifierExhausted => "identifier_exhausted",
190        ErrorCode::LegacyReplayUnavailable => "legacy_replay_unavailable",
191        ErrorCode::LateIngress => "late_ingress",
192        ErrorCode::MissingIdempotencyKey => "missing_idempotency_key",
193        ErrorCode::MixedCommandIngress => "mixed_command_ingress",
194        ErrorCode::NoRoute => "no_route",
195        ErrorCode::PluginCommandNotFound => "plugin_command_not_found",
196        ErrorCode::PluginManifestMismatch => "plugin_manifest_mismatch",
197        ErrorCode::PluginNotActive => "plugin_not_active",
198        ErrorCode::PluginPanicked => "plugin_panicked",
199        ErrorCode::PluginRegistrationClosed => "plugin_registration_closed",
200        ErrorCode::QueryBudgetExceeded => "query_budget_exceeded",
201        ErrorCode::ReplayMismatch => "replay_mismatch",
202        ErrorCode::ReplayEnvironmentMismatch => "replay_environment_mismatch",
203        ErrorCode::SimulationRevisionConflict => "simulation_revision_conflict",
204        ErrorCode::SimulationTimeConflict => "simulation_time_conflict",
205        ErrorCode::StaleSealToken => "stale_seal_token",
206        ErrorCode::StatePageUnavailable => "state_page_unavailable",
207        ErrorCode::SynchronousReactionLimit => "synchronous_reaction_limit",
208        ErrorCode::UndeclaredRandomStream => "undeclared_random_stream",
209        ErrorCode::UndeclaredStateRead => "undeclared_state_read",
210        ErrorCode::UndeclaredStateWrite => "undeclared_state_write",
211        ErrorCode::UnsupportedSnapshotVersion => "unsupported_snapshot_version",
212        ErrorCode::UnsupportedRandomDrawAddress => "unsupported_random_draw_address",
213        ErrorCode::ValueOutOfRange => "value_out_of_range",
214        ErrorCode::IssuerUnavailable => "issuer_unavailable",
215        ErrorCode::DecisionMakerUnavailable => "decision_maker_unavailable",
216        ErrorCode::EvaluationTraceLimitExceeded => "evaluation_trace_limit_exceeded",
217        ErrorCode::TransitionParticipantMissing => "transition_participant_missing",
218        ErrorCode::TransitionVersionMismatch => "transition_version_mismatch",
219    }
220}