1#[cfg(test)]
9mod tests;
10
11use candid::CandidType;
12use icydb_diagnostic_code as diagnostic_code;
13use serde::Deserialize;
14use std::fmt;
15
16pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
17const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
18const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
19const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
20const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
21const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
22
23const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
24 match origin {
25 ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
26 ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
27 ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
28 ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
29 ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
30 COMPACT_QUERY_DIAGNOSTIC_MESSAGE
31 }
32 ErrorOrigin::Cursor
33 | ErrorOrigin::Recovery
34 | ErrorOrigin::Executor
35 | ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
36 }
37}
38
39#[derive(Clone, Copy, Debug)]
135pub(crate) struct MutationDiagnosticContext {
136 fingerprint_method: u8,
137 accepted_schema_fingerprint: [u8; 16],
138 entity_tag: u64,
139 operation: diagnostic_code::DiagnosticMutationOperation,
140 batch_position: Option<u32>,
141}
142
143impl MutationDiagnosticContext {
144 #[must_use]
146 pub(crate) const fn new(
147 fingerprint_method: u8,
148 accepted_schema_fingerprint: [u8; 16],
149 entity_tag: u64,
150 operation: diagnostic_code::DiagnosticMutationOperation,
151 batch_position: u32,
152 ) -> Self {
153 Self {
154 fingerprint_method,
155 accepted_schema_fingerprint,
156 entity_tag,
157 operation,
158 batch_position: Some(batch_position),
159 }
160 }
161
162 #[must_use]
164 pub(crate) const fn operation_only(
165 fingerprint_method: u8,
166 accepted_schema_fingerprint: [u8; 16],
167 entity_tag: u64,
168 operation: diagnostic_code::DiagnosticMutationOperation,
169 ) -> Self {
170 Self {
171 fingerprint_method,
172 accepted_schema_fingerprint,
173 entity_tag,
174 operation,
175 batch_position: None,
176 }
177 }
178
179 fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
180 let mut facts = Vec::with_capacity(
181 5 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
182 );
183 append_accepted_schema_facts(
184 &mut facts,
185 self.fingerprint_method,
186 self.accepted_schema_fingerprint,
187 );
188 facts.push((
189 diagnostic_code::DiagnosticFactTag::EntityTag,
190 self.entity_tag,
191 ));
192 if let Some(field_id) = field_id {
193 facts.push((
194 diagnostic_code::DiagnosticFactTag::FieldId,
195 u64::from(field_id),
196 ));
197 }
198 self.append_operation_facts(&mut facts);
199 facts
200 }
201
202 #[must_use]
203 pub(crate) const fn entity_tag(self) -> u64 {
204 self.entity_tag
205 }
206
207 fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
208 facts.push((
209 diagnostic_code::DiagnosticFactTag::MutationOperation,
210 self.operation.raw(),
211 ));
212 if let Some(batch_position) = self.batch_position {
213 facts.push((
214 diagnostic_code::DiagnosticFactTag::BatchPosition,
215 u64::from(batch_position),
216 ));
217 }
218 }
219}
220
221pub struct DiagnosticFactDetail {
223 diagnostic: diagnostic_code::Diagnostic,
224 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
225}
226
227pub struct InternalError {
235 pub(crate) class: ErrorClass,
236 pub(crate) origin: ErrorOrigin,
237
238 pub(crate) detail: Option<ErrorDetail>,
241}
242
243#[expect(
244 clippy::missing_const_for_fn,
245 reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
246)]
247impl InternalError {
248 #[must_use]
252 #[cold]
253 #[inline(never)]
254 pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
255 let detail = match (class, origin) {
256 (ErrorClass::Corruption, ErrorOrigin::Store) => {
257 Some(ErrorDetail::Store(StoreError::Corrupt))
258 }
259 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
260 Some(ErrorDetail::Store(StoreError::InvariantViolation))
261 }
262 _ => None,
263 };
264
265 Self {
266 class,
267 origin,
268 detail,
269 }
270 }
271
272 #[must_use]
274 pub const fn class(&self) -> ErrorClass {
275 self.class
276 }
277
278 #[must_use]
280 pub const fn origin(&self) -> ErrorOrigin {
281 self.origin
282 }
283
284 #[must_use]
286 pub const fn message(&self) -> &'static str {
287 compact_message_for(self.class, self.origin)
288 }
289
290 #[must_use]
292 pub const fn detail(&self) -> Option<&ErrorDetail> {
293 self.detail.as_ref()
294 }
295
296 #[must_use]
298 pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
299 diagnostic_code::Diagnostic::new(
300 self.diagnostic_code(),
301 self.origin.diagnostic_origin(),
302 self.detail
303 .as_ref()
304 .and_then(ErrorDetail::diagnostic_detail),
305 )
306 }
307
308 #[must_use]
310 #[cold]
311 #[inline(never)]
312 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
313 self.detail
314 .as_ref()
315 .map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
316 }
317
318 #[must_use]
320 pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
321 self.detail.as_ref().map_or_else(
322 || self.class.diagnostic_code(self.origin),
323 ErrorDetail::diagnostic_code,
324 )
325 }
326
327 #[must_use]
329 pub fn into_message(self) -> String {
330 self.message().to_string()
331 }
332
333 #[cold]
335 #[inline(never)]
336 pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
337 Self::new(class, origin)
338 }
339
340 #[cold]
341 #[inline(never)]
342 fn with_diagnostic_facts(
343 class: ErrorClass,
344 origin: ErrorOrigin,
345 detail: Option<diagnostic_code::DiagnosticDetail>,
346 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
347 ) -> Self {
348 let code = match detail {
349 Some(detail) => detail.diagnostic_code(),
350 None => class.diagnostic_code(origin),
351 };
352 let diagnostic = diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), detail);
353 if diagnostic_code::validate_known_diagnostic_fact_schema(
354 diagnostic.error_code(),
355 facts.as_slice(),
356 )
357 .is_err()
358 {
359 return Self::new(ErrorClass::InvariantViolation, origin);
360 }
361 Self {
362 class,
363 origin,
364 detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
365 DiagnosticFactDetail { diagnostic, facts },
366 ))),
367 }
368 }
369
370 #[cold]
371 #[inline(never)]
372 fn mutation_boundary_with_facts(
373 class: ErrorClass,
374 boundary: diagnostic_code::RuntimeBoundaryCode,
375 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
376 ) -> Self {
377 Self::with_diagnostic_facts(
378 class,
379 ErrorOrigin::Executor,
380 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
381 facts,
382 )
383 }
384
385 #[cold]
386 #[inline(never)]
387 fn exact_key_batch_boundary_with_facts(
388 boundary: diagnostic_code::RuntimeBoundaryCode,
389 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
390 ) -> Self {
391 Self::with_diagnostic_facts(
392 ErrorClass::Unsupported,
393 ErrorOrigin::Query,
394 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
395 facts,
396 )
397 }
398
399 pub(crate) fn sql_query_entity_not_found() -> Self {
401 Self::with_diagnostic_facts(
402 ErrorClass::NotFound,
403 ErrorOrigin::Interface,
404 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
405 boundary: diagnostic_code::RuntimeBoundaryCode::SqlQueryEntityNotFound,
406 }),
407 Vec::new(),
408 )
409 }
410
411 #[cold]
413 #[inline(never)]
414 pub(crate) fn execution_budget_exceeded(
415 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
416 limit: u64,
417 observed: u64,
418 scope: diagnostic_code::DiagnosticExecutionBudgetScope,
419 lane: diagnostic_code::DiagnosticExecutionLane,
420 normalized_shape_fingerprint_prefix: u64,
421 ) -> Self {
422 Self::with_diagnostic_facts(
423 ErrorClass::Unsupported,
424 ErrorOrigin::Executor,
425 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
426 boundary: diagnostic_code::RuntimeBoundaryCode::ExecutionBudgetExceeded,
427 }),
428 vec![
429 (
430 diagnostic_code::DiagnosticFactTag::BudgetResource,
431 resource.raw(),
432 ),
433 (diagnostic_code::DiagnosticFactTag::Limit, limit),
434 (diagnostic_code::DiagnosticFactTag::Actual, observed),
435 (
436 diagnostic_code::DiagnosticFactTag::ExecutionBudgetScope,
437 scope.raw(),
438 ),
439 (
440 diagnostic_code::DiagnosticFactTag::ExecutionLane,
441 lane.raw(),
442 ),
443 (
444 diagnostic_code::DiagnosticFactTag::QueryShapeFingerprintPrefix,
445 normalized_shape_fingerprint_prefix,
446 ),
447 ],
448 )
449 }
450
451 #[cold]
453 #[inline(never)]
454 pub(crate) fn relation_budget_exceeded(
455 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
456 limit: u64,
457 observed: u64,
458 ) -> Self {
459 Self::execution_budget_exceeded(
460 resource,
461 limit,
462 observed,
463 diagnostic_code::DiagnosticExecutionBudgetScope::Execution,
464 diagnostic_code::DiagnosticExecutionLane::Mutation,
465 0,
466 )
467 }
468
469 #[cold]
471 #[inline(never)]
472 pub(crate) fn page_unit_too_large(
473 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
474 limit: u64,
475 attempted: u64,
476 ) -> Self {
477 Self::with_diagnostic_facts(
478 ErrorClass::Unsupported,
479 ErrorOrigin::Executor,
480 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
481 boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
482 }),
483 vec![
484 (
485 diagnostic_code::DiagnosticFactTag::BudgetResource,
486 resource.raw(),
487 ),
488 (diagnostic_code::DiagnosticFactTag::Limit, limit),
489 (diagnostic_code::DiagnosticFactTag::Actual, attempted),
490 ],
491 )
492 }
493
494 #[cold]
499 #[inline(never)]
500 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
501 match self.detail {
502 Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
503 self.class,
504 origin,
505 detail.diagnostic.detail().copied(),
506 detail.facts,
507 ),
508 _ => Self::classified(self.class, origin),
509 }
510 }
511
512 #[cold]
514 #[inline(never)]
515 pub(crate) fn index_invariant() -> Self {
516 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
517 }
518
519 pub(crate) fn index_key_field_count_exceeds_max(
521 entity_tag: u64,
522 physical_generation: u64,
523 field_count: usize,
524 max_fields: usize,
525 ) -> Self {
526 Self::with_diagnostic_facts(
527 ErrorClass::InvariantViolation,
528 ErrorOrigin::Index,
529 None,
530 vec![
531 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
532 (
533 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
534 physical_generation,
535 ),
536 (
537 diagnostic_code::DiagnosticFactTag::ComponentKind,
538 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
539 ),
540 (
541 diagnostic_code::DiagnosticFactTag::ActualArity,
542 field_count as u64,
543 ),
544 (
545 diagnostic_code::DiagnosticFactTag::Maximum,
546 max_fields as u64,
547 ),
548 ],
549 )
550 }
551
552 #[cold]
555 #[inline(never)]
556 pub(crate) fn planner_executor_invariant() -> Self {
557 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
558 }
559
560 #[cold]
563 #[inline(never)]
564 pub(crate) fn query_executor_invariant() -> Self {
565 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
566 }
567
568 #[cold]
571 #[inline(never)]
572 pub(crate) fn cursor_executor_invariant() -> Self {
573 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
574 }
575
576 #[cold]
578 #[inline(never)]
579 pub(crate) fn executor_invariant() -> Self {
580 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
581 }
582
583 #[cold]
585 #[inline(never)]
586 pub(crate) fn executor_internal() -> Self {
587 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
588 }
589
590 #[cold]
592 #[inline(never)]
593 pub(crate) fn executor_unsupported() -> Self {
594 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
595 }
596
597 #[cold]
599 #[inline(never)]
600 pub(crate) fn mutation_database_owned_field_explicit(
601 context: MutationDiagnosticContext,
602 field_id: u32,
603 ) -> Self {
604 Self::mutation_boundary_with_facts(
605 ErrorClass::Unsupported,
606 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
607 context.facts(Some(field_id)),
608 )
609 }
610
611 #[must_use]
613 #[cold]
614 #[inline(never)]
615 pub(crate) fn mutation_required_field_missing(
616 context: MutationDiagnosticContext,
617 field_id: u32,
618 ) -> Self {
619 Self::mutation_boundary_with_facts(
620 ErrorClass::Unsupported,
621 diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
622 context.facts(Some(field_id)),
623 )
624 }
625
626 #[must_use]
628 #[cold]
629 #[inline(never)]
630 pub(crate) fn mutation_managed_timestamp_regression(
631 context: MutationDiagnosticContext,
632 ) -> Self {
633 Self::mutation_boundary_with_facts(
634 ErrorClass::InvariantViolation,
635 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
636 context.facts(None),
637 )
638 }
639
640 pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
642 Self::mutation_boundary_with_facts(
643 ErrorClass::InvariantViolation,
644 diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
645 context.facts(),
646 )
647 }
648
649 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
651 Self {
652 class: ErrorClass::Corruption,
653 origin: ErrorOrigin::Executor,
654 detail: Some(ErrorDetail::Executor(
655 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
656 )),
657 }
658 }
659
660 pub(crate) fn mutation_constraint_activation_write_blocked(
662 context: AcceptedConstraintFactContext,
663 ) -> Self {
664 Self::mutation_boundary_with_facts(
665 ErrorClass::Conflict,
666 diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
667 context.facts(),
668 )
669 }
670
671 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
673 Self::query_executor_invariant()
674 }
675
676 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
678 Self::query_executor_invariant()
679 }
680
681 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
683 Self::query_executor_invariant()
684 }
685
686 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
688 Self::query_executor_invariant()
689 }
690
691 pub(crate) fn index_range_limit_spec_required() -> Self {
693 Self::query_executor_invariant()
694 }
695
696 #[cold]
698 #[inline(never)]
699 pub(crate) fn mutation_atomic_save_duplicate_key(
700 entity_tag: u64,
701 first_position: u32,
702 duplicate_position: u32,
703 ) -> Self {
704 Self::mutation_boundary_with_facts(
705 ErrorClass::Conflict,
706 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
707 vec![
708 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
709 (
710 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
711 u64::from(first_position),
712 ),
713 (
714 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
715 u64::from(duplicate_position),
716 ),
717 ],
718 )
719 }
720
721 #[cold]
723 #[inline(never)]
724 pub(crate) fn mutation_batch_empty() -> Self {
725 Self::mutation_boundary_with_facts(
726 ErrorClass::Unsupported,
727 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
728 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
729 )
730 }
731
732 #[cold]
734 #[inline(never)]
735 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
736 Self::mutation_boundary_with_facts(
737 ErrorClass::Unsupported,
738 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
739 vec![
740 (
741 diagnostic_code::DiagnosticFactTag::ActualCount,
742 actual_count as u64,
743 ),
744 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
745 ],
746 )
747 }
748
749 #[cold]
751 #[inline(never)]
752 pub(crate) fn mutation_batch_staged_bytes_exceeded(
753 actual_bytes: Option<usize>,
754 limit: usize,
755 ) -> Self {
756 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
757 if let Some(actual_bytes) = actual_bytes {
758 facts.push((
759 diagnostic_code::DiagnosticFactTag::ActualLength,
760 actual_bytes as u64,
761 ));
762 }
763 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
764 Self::mutation_boundary_with_facts(
765 ErrorClass::Unsupported,
766 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
767 facts,
768 )
769 }
770
771 #[cold]
773 #[inline(never)]
774 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
775 Self::mutation_boundary_with_facts(
776 ErrorClass::Unsupported,
777 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
778 vec![
779 (
780 diagnostic_code::DiagnosticFactTag::ActualLength,
781 actual_bytes as u64,
782 ),
783 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
784 ],
785 )
786 }
787
788 #[cold]
790 #[inline(never)]
791 pub(crate) fn mutation_batch_commit_work_exceeded(
792 actual_units: Option<usize>,
793 limit: usize,
794 ) -> Self {
795 let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
796 if let Some(actual_units) = actual_units {
797 facts.push((
798 diagnostic_code::DiagnosticFactTag::ActualCount,
799 actual_units as u64,
800 ));
801 }
802 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
803 Self::mutation_boundary_with_facts(
804 ErrorClass::Unsupported,
805 diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
806 facts,
807 )
808 }
809
810 pub(crate) fn convergence_backlog_pressure(
812 resource: diagnostic_code::DiagnosticBacklogResource,
813 current: u64,
814 proposed: u64,
815 limit: u64,
816 ) -> Self {
817 Self::mutation_boundary_with_facts(
818 ErrorClass::Conflict,
819 diagnostic_code::RuntimeBoundaryCode::ConvergenceBacklogPressure,
820 vec![
821 (
822 diagnostic_code::DiagnosticFactTag::BacklogResource,
823 resource.raw(),
824 ),
825 (diagnostic_code::DiagnosticFactTag::CurrentCount, current),
826 (diagnostic_code::DiagnosticFactTag::ProposedCount, proposed),
827 (diagnostic_code::DiagnosticFactTag::Limit, limit),
828 ],
829 )
830 }
831
832 #[cold]
834 #[inline(never)]
835 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
836 Self::exact_key_batch_boundary_with_facts(
837 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
838 vec![
839 (
840 diagnostic_code::DiagnosticFactTag::ActualCount,
841 actual_count as u64,
842 ),
843 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
844 ],
845 )
846 }
847
848 #[cold]
850 #[inline(never)]
851 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
852 Self::exact_key_batch_bytes_exceeded(
853 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
854 actual_bytes,
855 limit,
856 )
857 }
858
859 #[cold]
861 #[inline(never)]
862 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
863 Self::exact_key_batch_bytes_exceeded(
864 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
865 actual_bytes,
866 limit,
867 )
868 }
869
870 #[cold]
872 #[inline(never)]
873 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
874 Self::exact_key_batch_bytes_exceeded(
875 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
876 actual_bytes,
877 limit,
878 )
879 }
880
881 #[cold]
882 #[inline(never)]
883 fn exact_key_batch_bytes_exceeded(
884 boundary: diagnostic_code::RuntimeBoundaryCode,
885 actual_bytes: usize,
886 limit: usize,
887 ) -> Self {
888 Self::exact_key_batch_boundary_with_facts(
889 boundary,
890 vec![
891 (
892 diagnostic_code::DiagnosticFactTag::ActualLength,
893 actual_bytes as u64,
894 ),
895 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
896 ],
897 )
898 }
899
900 #[cold]
902 #[inline(never)]
903 pub(crate) fn mutation_batch_store_mismatch(
904 batch_position: u32,
905 expected_entity_tag: u64,
906 actual_entity_tag: u64,
907 ) -> Self {
908 Self::mutation_boundary_with_facts(
909 ErrorClass::Conflict,
910 diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
911 vec![
912 (
913 diagnostic_code::DiagnosticFactTag::BatchPosition,
914 u64::from(batch_position),
915 ),
916 (
917 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
918 expected_entity_tag,
919 ),
920 (
921 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
922 actual_entity_tag,
923 ),
924 ],
925 )
926 }
927
928 #[cold]
930 #[inline(never)]
931 pub(crate) fn mutation_batch_too_many_entities(actual_count: usize, limit: usize) -> Self {
932 Self::mutation_boundary_with_facts(
933 ErrorClass::Unsupported,
934 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
935 vec![
936 (
937 diagnostic_code::DiagnosticFactTag::ActualCount,
938 actual_count as u64,
939 ),
940 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
941 ],
942 )
943 }
944
945 #[cold]
947 #[inline(never)]
948 pub(crate) fn planner_invariant() -> Self {
949 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
950 }
951
952 pub(crate) fn query_invalid_logical_plan() -> Self {
954 Self::planner_invariant()
955 }
956
957 pub(crate) fn store_invariant() -> Self {
959 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
960 }
961
962 #[cold]
964 #[inline(never)]
965 pub(crate) fn store_internal() -> Self {
966 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
967 }
968
969 pub(crate) fn commit_memory_id_unconfigured() -> Self {
971 Self::store_internal()
972 }
973
974 pub(crate) fn commit_store_uninitialized() -> Self {
976 Self::store_invariant()
977 }
978
979 pub(crate) fn database_incarnation_generation_failed() -> Self {
981 Self::store_internal()
982 }
983
984 pub(crate) fn database_incarnation_invalid() -> Self {
986 Self::store_corruption()
987 }
988
989 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
991 Self {
992 class: ErrorClass::IncompatiblePersistedFormat,
993 origin: ErrorOrigin::Recovery,
994 detail: Some(ErrorDetail::Recovery(
995 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
996 )),
997 }
998 }
999
1000 pub(crate) fn recovery_malformed_database_format_marker(
1002 reason: RecoveryFormatMarkerError,
1003 ) -> Self {
1004 Self {
1005 class: ErrorClass::Corruption,
1006 origin: ErrorOrigin::Recovery,
1007 detail: Some(ErrorDetail::Recovery(
1008 RecoveryErrorDetail::MalformedFormatMarker { reason },
1009 )),
1010 }
1011 }
1012
1013 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1015 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1016 }
1017
1018 pub(crate) fn recovery_pending() -> Self {
1020 Self::with_diagnostic_facts(
1021 ErrorClass::Conflict,
1022 ErrorOrigin::Recovery,
1023 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1024 boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1025 }),
1026 Vec::new(),
1027 )
1028 }
1029
1030 pub(crate) fn startup_control_corruption() -> Self {
1032 Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1033 }
1034
1035 pub(crate) fn commit_control_memory_growth_failed() -> Self {
1037 Self::store_internal()
1038 }
1039
1040 pub(crate) fn recovery_effect_verification_failed() -> Self {
1042 Self::store_corruption()
1043 }
1044
1045 #[cold]
1047 #[inline(never)]
1048 pub(crate) fn index_internal() -> Self {
1049 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1050 }
1051
1052 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1054 Self::index_internal()
1055 }
1056
1057 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1059 Self::index_internal()
1060 }
1061
1062 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1064 Self::index_internal()
1065 }
1066
1067 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1069 Self::index_internal()
1070 }
1071
1072 #[cfg(test)]
1074 pub(crate) fn query_internal() -> Self {
1075 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1076 }
1077
1078 #[cold]
1080 #[inline(never)]
1081 pub(crate) fn query_unsupported() -> Self {
1082 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1083 }
1084
1085 #[cold]
1087 #[inline(never)]
1088 pub(crate) fn query_exact_count_metadata_unavailable() -> Self {
1089 Self {
1090 class: ErrorClass::Unsupported,
1091 origin: ErrorOrigin::Query,
1092 detail: Some(ErrorDetail::Query(
1093 QueryErrorDetail::ExactCountMetadataUnavailable,
1094 )),
1095 }
1096 }
1097
1098 pub(crate) fn query_explain_output_exceeded(limit: u64, observed: u64) -> Self {
1101 Self::with_diagnostic_facts(
1102 ErrorClass::Unsupported,
1103 ErrorOrigin::Query,
1104 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1105 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainOutputExceeded,
1106 }),
1107 vec![
1108 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1109 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1110 ],
1111 )
1112 }
1113
1114 pub(crate) fn query_explain_depth_exceeded(limit: u64, observed: u64) -> Self {
1117 Self::with_diagnostic_facts(
1118 ErrorClass::Unsupported,
1119 ErrorOrigin::Query,
1120 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1121 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainDepthExceeded,
1122 }),
1123 vec![
1124 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1125 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1126 ],
1127 )
1128 }
1129
1130 #[cold]
1133 #[inline(never)]
1134 pub(crate) fn query_stale_accepted_schema_revision(
1135 expected_revision: u64,
1136 current_revision: Option<u64>,
1137 ) -> Self {
1138 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1139 facts.push((
1140 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1141 expected_revision,
1142 ));
1143 if let Some(current_revision) = current_revision {
1144 facts.push((
1145 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1146 current_revision,
1147 ));
1148 }
1149 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1150 }
1151
1152 #[cold]
1154 #[inline(never)]
1155 #[cfg(feature = "sql")]
1156 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1157 Self {
1158 class: ErrorClass::Unsupported,
1159 origin: ErrorOrigin::Query,
1160 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1161 error,
1162 })),
1163 }
1164 }
1165
1166 #[cold]
1168 #[inline(never)]
1169 pub(crate) fn query_numeric_overflow() -> Self {
1170 Self {
1171 class: ErrorClass::Unsupported,
1172 origin: ErrorOrigin::Query,
1173 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1174 }
1175 }
1176
1177 #[cold]
1180 #[inline(never)]
1181 pub(crate) fn query_numeric_not_representable() -> Self {
1182 Self {
1183 class: ErrorClass::Unsupported,
1184 origin: ErrorOrigin::Query,
1185 detail: Some(ErrorDetail::Query(
1186 QueryErrorDetail::NumericNotRepresentable,
1187 )),
1188 }
1189 }
1190
1191 #[cold]
1193 #[inline(never)]
1194 pub(crate) fn serialize_internal() -> Self {
1195 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1196 }
1197
1198 pub(crate) fn persisted_row_encode_internal() -> Self {
1200 Self::serialize_internal()
1201 }
1202
1203 #[cold]
1205 #[inline(never)]
1206 pub(crate) fn store_corruption() -> Self {
1207 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1208 }
1209
1210 pub(crate) fn commit_corruption() -> Self {
1212 Self::store_corruption()
1213 }
1214
1215 pub(crate) fn commit_component_corruption() -> Self {
1217 Self::commit_corruption()
1218 }
1219
1220 pub(crate) fn commit_id_generation_failed() -> Self {
1222 Self::store_internal()
1223 }
1224
1225 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1227 Self::store_unsupported()
1228 }
1229
1230 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1232 Self::with_diagnostic_facts(
1233 ErrorClass::Corruption,
1234 ErrorOrigin::Store,
1235 None,
1236 vec![
1237 (
1238 diagnostic_code::DiagnosticFactTag::ComponentKind,
1239 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1240 ),
1241 (
1242 diagnostic_code::DiagnosticFactTag::ActualLength,
1243 actual_length as u64,
1244 ),
1245 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1246 ],
1247 )
1248 }
1249
1250 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1252 Self::commit_corruption()
1253 }
1254
1255 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1257 Self::store_unsupported()
1258 }
1259
1260 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1262 Self::store_unsupported()
1263 }
1264
1265 #[cold]
1267 #[inline(never)]
1268 pub(crate) fn index_corruption() -> Self {
1269 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1270 }
1271
1272 pub(crate) fn index_unique_validation_corruption() -> Self {
1274 Self::index_plan_index_corruption()
1275 }
1276
1277 pub(crate) fn structural_index_entry_corruption() -> Self {
1279 Self::index_plan_index_corruption()
1280 }
1281
1282 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1284 Self::index_invariant()
1285 }
1286
1287 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1289 Self::index_plan_serialize_corruption()
1290 }
1291
1292 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1294 Self::index_plan_serialize_corruption()
1295 }
1296
1297 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1299 Self::index_plan_serialize_corruption()
1300 }
1301
1302 pub(crate) fn index_unique_validation_row_required() -> Self {
1304 Self::index_plan_store_corruption()
1305 }
1306
1307 pub(crate) fn index_only_predicate_component_required() -> Self {
1309 Self::index_invariant()
1310 }
1311
1312 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1314 Self::index_invariant()
1315 }
1316
1317 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1319 Self::index_invariant()
1320 }
1321
1322 pub(crate) fn index_entry_decode_failed() -> Self {
1324 Self::index_corruption()
1325 }
1326
1327 pub(crate) fn serialize_corruption() -> Self {
1329 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1330 }
1331
1332 pub(crate) fn persisted_row_decode_corruption() -> Self {
1334 Self::serialize_corruption()
1335 }
1336
1337 pub(crate) fn persisted_row_layout_outside_accepted_window(
1339 row_layout: u32,
1340 history_floor: u32,
1341 current_layout: u32,
1342 ) -> Self {
1343 Self::with_diagnostic_facts(
1344 ErrorClass::Corruption,
1345 ErrorOrigin::Serialize,
1346 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1347 boundary:
1348 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1349 }),
1350 vec![
1351 (
1352 diagnostic_code::DiagnosticFactTag::RowLayout,
1353 u64::from(row_layout),
1354 ),
1355 (
1356 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1357 u64::from(history_floor),
1358 ),
1359 (
1360 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1361 u64::from(current_layout),
1362 ),
1363 ],
1364 )
1365 }
1366
1367 pub(crate) fn persisted_row_slot_count_mismatch(
1369 row_layout: u32,
1370 expected_slot_count: usize,
1371 actual_slot_count: usize,
1372 ) -> Self {
1373 Self::with_diagnostic_facts(
1374 ErrorClass::Corruption,
1375 ErrorOrigin::Serialize,
1376 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1377 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1378 }),
1379 vec![
1380 (
1381 diagnostic_code::DiagnosticFactTag::RowLayout,
1382 u64::from(row_layout),
1383 ),
1384 (
1385 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1386 expected_slot_count as u64,
1387 ),
1388 (
1389 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1390 actual_slot_count as u64,
1391 ),
1392 ],
1393 )
1394 }
1395
1396 pub(crate) fn persisted_row_key_mismatch() -> Self {
1398 Self::store_corruption()
1399 }
1400
1401 pub(crate) fn with_relation_identity(self, entity_tag: u64, relation_id: u32) -> Self {
1403 if self.diagnostic().error_code() != diagnostic_code::ErrorCode::RUNTIME_INTERNAL {
1404 return self;
1405 }
1406 let mut facts = vec![
1407 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1408 (
1409 diagnostic_code::DiagnosticFactTag::RelationId,
1410 u64::from(relation_id),
1411 ),
1412 ];
1413 facts.extend(self.diagnostic_facts());
1414 Self::with_diagnostic_facts(self.class, self.origin, None, facts)
1415 }
1416
1417 pub(crate) fn relation_target_primary_key_arity_mismatch(
1419 expected_arity: usize,
1420 actual_arity: usize,
1421 ) -> Self {
1422 Self::with_diagnostic_facts(
1423 ErrorClass::Internal,
1424 ErrorOrigin::Executor,
1425 None,
1426 vec![
1427 (
1428 diagnostic_code::DiagnosticFactTag::ComponentKind,
1429 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1430 ),
1431 (
1432 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1433 expected_arity as u64,
1434 ),
1435 (
1436 diagnostic_code::DiagnosticFactTag::ActualArity,
1437 actual_arity as u64,
1438 ),
1439 ],
1440 )
1441 }
1442
1443 pub(crate) fn relation_target_entity_mismatch(expected_tag: u64, actual_tag: u64) -> Self {
1445 Self::with_diagnostic_facts(
1446 ErrorClass::Corruption,
1447 ErrorOrigin::Store,
1448 None,
1449 vec![
1450 (
1451 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1452 expected_tag,
1453 ),
1454 (
1455 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1456 actual_tag,
1457 ),
1458 ],
1459 )
1460 }
1461
1462 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1464 Self::index_corruption()
1465 }
1466
1467 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1469 Self::index_corruption()
1470 }
1471
1472 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1474 Self::index_corruption()
1475 }
1476
1477 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1479 Self::index_corruption()
1480 }
1481
1482 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1484 Self::index_corruption()
1485 }
1486
1487 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1489 Self::index_corruption()
1490 }
1491
1492 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1494 Self::index_corruption()
1495 }
1496
1497 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1499 Self::index_corruption()
1500 }
1501
1502 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1504 Self::index_corruption()
1505 }
1506
1507 pub(crate) fn identity_corruption() -> Self {
1509 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1510 }
1511
1512 pub(crate) fn identity_state_corruption() -> Self {
1514 Self::identity_corruption()
1515 }
1516
1517 pub(crate) fn identity_state_conflict() -> Self {
1519 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1520 }
1521
1522 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1524 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1525 }
1526
1527 pub(crate) fn identity_exhausted() -> Self {
1529 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1530 }
1531
1532 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1534 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1535 }
1536
1537 #[cold]
1539 #[inline(never)]
1540 pub(crate) fn store_unsupported() -> Self {
1541 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1542 }
1543
1544 pub(crate) fn schema_application_conflict() -> Self {
1546 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1547 }
1548
1549 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1551 let class = match reason.diagnostic_code() {
1552 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1553 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1554 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1555 _ => ErrorClass::Internal,
1556 };
1557 Self {
1558 class,
1559 origin: ErrorOrigin::Store,
1560 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1561 }
1562 }
1563
1564 pub(crate) fn schema_ddl_publication_race_lost() -> Self {
1566 Self {
1567 class: ErrorClass::Unsupported,
1568 origin: ErrorOrigin::Store,
1569 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1570 }
1571 }
1572
1573 #[cfg(feature = "sql")]
1575 pub(crate) fn schema_ddl_rewrite_requires_migration() -> Self {
1576 Self {
1577 class: ErrorClass::Unsupported,
1578 origin: ErrorOrigin::Store,
1579 detail: Some(ErrorDetail::Store(
1580 StoreError::SchemaDdlRewriteRequiresMigration,
1581 )),
1582 }
1583 }
1584
1585 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1587 Self {
1588 class: ErrorClass::Unsupported,
1589 origin: ErrorOrigin::Store,
1590 detail: Some(ErrorDetail::Store(
1591 StoreError::JournalMutationRevisionExhausted,
1592 )),
1593 }
1594 }
1595
1596 pub(crate) fn schema_transition_budget_exceeded(
1598 resource: SchemaTransitionBudgetResource,
1599 ) -> Self {
1600 Self {
1601 class: ErrorClass::Unsupported,
1602 origin: ErrorOrigin::Store,
1603 detail: Some(ErrorDetail::Store(
1604 StoreError::SchemaTransitionBudgetExceeded { resource },
1605 )),
1606 }
1607 }
1608
1609 pub(crate) fn index_unsupported() -> Self {
1611 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1612 }
1613
1614 pub(crate) fn index_component_exceeds_max_size_at(
1616 entity_tag: u64,
1617 physical_generation: u64,
1618 component_index: usize,
1619 actual_length: usize,
1620 limit: usize,
1621 ) -> Self {
1622 Self::with_diagnostic_facts(
1623 ErrorClass::Unsupported,
1624 ErrorOrigin::Index,
1625 None,
1626 vec![
1627 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1628 (
1629 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1630 physical_generation,
1631 ),
1632 (
1633 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1634 component_index as u64,
1635 ),
1636 (
1637 diagnostic_code::DiagnosticFactTag::ComponentKind,
1638 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1639 ),
1640 (
1641 diagnostic_code::DiagnosticFactTag::ActualLength,
1642 actual_length as u64,
1643 ),
1644 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1645 ],
1646 )
1647 }
1648
1649 pub(crate) fn index_component_exceeds_max_size() -> Self {
1652 Self::index_unsupported()
1653 }
1654
1655 pub(crate) fn serialize_unsupported() -> Self {
1657 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1658 }
1659
1660 pub(crate) fn cursor_invalid_continuation() -> Self {
1662 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1663 }
1664
1665 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1667 Self::new(
1668 ErrorClass::IncompatiblePersistedFormat,
1669 ErrorOrigin::Serialize,
1670 )
1671 }
1672
1673 #[cfg(feature = "sql")]
1676 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1677 Self {
1678 class: ErrorClass::Unsupported,
1679 origin: ErrorOrigin::Query,
1680 detail: Some(ErrorDetail::Query(
1681 QueryErrorDetail::UnsupportedSqlFeature { feature },
1682 )),
1683 }
1684 }
1685
1686 #[cfg(feature = "sql")]
1689 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1690 Self {
1691 class: ErrorClass::Unsupported,
1692 origin: ErrorOrigin::Query,
1693 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1694 }
1695 }
1696
1697 #[cfg(feature = "sql")]
1699 pub(crate) fn query_sql_lowering_with_facts(
1700 reason: diagnostic_code::SqlLoweringCode,
1701 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1702 ) -> Self {
1703 Self::with_diagnostic_facts(
1704 ErrorClass::Unsupported,
1705 ErrorOrigin::Query,
1706 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1707 facts,
1708 )
1709 }
1710
1711 pub(crate) fn query_unsupported_projection(
1714 reason: diagnostic_code::QueryProjectionCode,
1715 ) -> Self {
1716 Self {
1717 class: ErrorClass::Unsupported,
1718 origin: ErrorOrigin::Query,
1719 detail: Some(ErrorDetail::Query(
1720 QueryErrorDetail::UnsupportedProjection { reason },
1721 )),
1722 }
1723 }
1724
1725 #[cfg(feature = "sql")]
1728 pub(crate) fn query_sql_surface_mismatch(
1729 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1730 ) -> Self {
1731 Self {
1732 class: ErrorClass::Unsupported,
1733 origin: ErrorOrigin::Query,
1734 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1735 mismatch,
1736 })),
1737 }
1738 }
1739
1740 pub(crate) fn query_sql_write_boundary(
1742 boundary: diagnostic_code::SqlWriteBoundaryCode,
1743 ) -> Self {
1744 Self {
1745 class: ErrorClass::Unsupported,
1746 origin: ErrorOrigin::Query,
1747 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1748 boundary,
1749 })),
1750 }
1751 }
1752
1753 pub(crate) fn query_sql_write_boundary_with_facts(
1755 boundary: diagnostic_code::SqlWriteBoundaryCode,
1756 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1757 ) -> Self {
1758 Self::with_diagnostic_facts(
1759 ErrorClass::Unsupported,
1760 ErrorOrigin::Query,
1761 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1762 facts,
1763 )
1764 }
1765
1766 pub fn store_not_found(_key: impl Sized) -> Self {
1767 Self {
1768 class: ErrorClass::NotFound,
1769 origin: ErrorOrigin::Store,
1770 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1771 }
1772 }
1773
1774 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1776 Self::store_unsupported()
1777 }
1778
1779 #[cold]
1781 #[inline(never)]
1782 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1783 Self::new(ErrorClass::Corruption, origin)
1784 }
1785
1786 #[cold]
1788 #[inline(never)]
1789 pub(crate) fn index_plan_index_corruption() -> Self {
1790 Self::index_plan_corruption(ErrorOrigin::Index)
1791 }
1792
1793 #[cold]
1795 #[inline(never)]
1796 pub(crate) fn index_plan_store_corruption() -> Self {
1797 Self::index_plan_corruption(ErrorOrigin::Store)
1798 }
1799
1800 #[cold]
1802 #[inline(never)]
1803 pub(crate) fn index_plan_serialize_corruption() -> Self {
1804 Self::index_plan_corruption(ErrorOrigin::Serialize)
1805 }
1806
1807 #[cfg(test)]
1809 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1810 Self::new(ErrorClass::InvariantViolation, origin)
1811 }
1812
1813 #[cfg(test)]
1815 pub(crate) fn index_plan_store_invariant() -> Self {
1816 Self::index_plan_invariant(ErrorOrigin::Store)
1817 }
1818
1819 pub(crate) fn index_conflict() -> Self {
1825 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1826 }
1827}
1828
1829impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1830 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1831 Self {
1832 class: ErrorClass::Unsupported,
1833 origin: ErrorOrigin::Query,
1834 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1835 reason,
1836 })),
1837 }
1838 }
1839}
1840
1841impl fmt::Debug for InternalError {
1842 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1843 fmt_compact_diagnostic(
1844 f,
1845 self.diagnostic_code(),
1846 self.detail
1847 .as_ref()
1848 .and_then(ErrorDetail::diagnostic_detail),
1849 )
1850 }
1851}
1852
1853impl fmt::Display for InternalError {
1854 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1855 f.write_str(self.message())
1856 }
1857}
1858
1859impl std::error::Error for InternalError {}
1860
1861#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1870pub enum ConstraintValuePathComponent {
1871 RootField { field_id: u32 },
1873
1874 RecordMember {
1876 composite_type_id: u32,
1877 member_id: u32,
1878 },
1879
1880 TupleElement {
1882 composite_type_id: u32,
1883 ordinal: u32,
1884 },
1885
1886 Newtype { composite_type_id: u32 },
1888
1889 EnumVariant { enum_type_id: u32, variant_id: u32 },
1891
1892 ListElement { index: u32 },
1894
1895 SetElement { index: u32 },
1897
1898 MapEntryKey { index: u32 },
1900
1901 MapEntryValue { index: u32 },
1903}
1904
1905impl fmt::Display for ConstraintValuePathComponent {
1906 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1907 match self {
1908 Self::RootField { field_id } => write!(f, "field#{field_id}"),
1909 Self::RecordMember {
1910 composite_type_id,
1911 member_id,
1912 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
1913 Self::TupleElement {
1914 composite_type_id,
1915 ordinal,
1916 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
1917 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
1918 Self::EnumVariant {
1919 enum_type_id,
1920 variant_id,
1921 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
1922 Self::ListElement { index } => write!(f, "list[{index}]"),
1923 Self::SetElement { index } => write!(f, "set[{index}]"),
1924 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
1925 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
1926 }
1927 }
1928}
1929
1930#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1937pub struct ConstraintValuePath {
1938 components: Vec<ConstraintValuePathComponent>,
1939}
1940
1941impl ConstraintValuePath {
1942 #[must_use]
1944 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
1945 Self { components }
1946 }
1947
1948 #[must_use]
1950 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
1951 self.components.as_slice()
1952 }
1953}
1954
1955impl fmt::Display for ConstraintValuePath {
1956 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1957 for (ordinal, component) in self.components.iter().enumerate() {
1958 if ordinal != 0 {
1959 f.write_str("/")?;
1960 }
1961 component.fmt(f)?;
1962 }
1963 Ok(())
1964 }
1965}
1966
1967#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1976pub struct ConstraintValidationFindingOutput {
1977 accepted_schema_fingerprint: [u8; 16],
1978 entity_tag: u64,
1979 constraint_id: u32,
1980 primary_key: Vec<u8>,
1981 field_ids: Vec<u32>,
1982 value_path: Option<ConstraintValuePath>,
1983 error_code: u16,
1984}
1985
1986impl ConstraintValidationFindingOutput {
1987 #[must_use]
1989 pub(crate) const fn new(
1990 accepted_schema_fingerprint: [u8; 16],
1991 entity_tag: u64,
1992 constraint_id: u32,
1993 primary_key: Vec<u8>,
1994 field_ids: Vec<u32>,
1995 value_path: Option<ConstraintValuePath>,
1996 error_code: u16,
1997 ) -> Self {
1998 Self {
1999 accepted_schema_fingerprint,
2000 entity_tag,
2001 constraint_id,
2002 primary_key,
2003 field_ids,
2004 value_path,
2005 error_code,
2006 }
2007 }
2008
2009 #[must_use]
2011 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2012 self.accepted_schema_fingerprint
2013 }
2014
2015 #[must_use]
2017 pub const fn entity_tag(&self) -> u64 {
2018 self.entity_tag
2019 }
2020
2021 #[must_use]
2023 pub const fn constraint_id(&self) -> u32 {
2024 self.constraint_id
2025 }
2026
2027 #[must_use]
2029 pub const fn primary_key(&self) -> &[u8] {
2030 self.primary_key.as_slice()
2031 }
2032
2033 #[must_use]
2035 pub const fn field_ids(&self) -> &[u32] {
2036 self.field_ids.as_slice()
2037 }
2038
2039 #[must_use]
2041 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2042 self.value_path.as_ref()
2043 }
2044
2045 #[must_use]
2047 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2048 diagnostic_code::ErrorCode::from_raw(self.error_code)
2049 }
2050
2051 #[must_use]
2053 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2054 self.error_code().class()
2055 }
2056}
2057
2058#[derive(Clone)]
2060pub(crate) struct AcceptedConstraintFactContext {
2061 fingerprint_method: u8,
2062 accepted_schema_fingerprint: [u8; 16],
2063 entity_tag: u64,
2064 constraint_id: u32,
2065 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2066 mutation: Option<MutationDiagnosticContext>,
2067 value_path: Option<ConstraintValuePath>,
2068}
2069
2070impl AcceptedConstraintFactContext {
2071 #[must_use]
2072 pub(crate) fn write_admission(
2073 fingerprint_method: u8,
2074 accepted_schema_fingerprint: [u8; 16],
2075 entity_tag: u64,
2076 constraint_id: u32,
2077 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2078 mutation: Option<MutationDiagnosticContext>,
2079 value_path: Option<ConstraintValuePath>,
2080 ) -> Self {
2081 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2082 Self {
2083 fingerprint_method,
2084 accepted_schema_fingerprint,
2085 entity_tag,
2086 constraint_id,
2087 constraint_kind,
2088 mutation,
2089 value_path,
2090 }
2091 }
2092
2093 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2094 let path_len = self
2095 .value_path
2096 .as_ref()
2097 .map_or(0, |path| path.components().len());
2098 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2099 1 + usize::from(mutation.batch_position.is_some())
2100 });
2101 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2102 append_accepted_schema_facts(
2103 &mut facts,
2104 self.fingerprint_method,
2105 self.accepted_schema_fingerprint,
2106 );
2107 facts.push((
2108 diagnostic_code::DiagnosticFactTag::EntityTag,
2109 self.entity_tag,
2110 ));
2111 facts.push((
2112 diagnostic_code::DiagnosticFactTag::ConstraintId,
2113 u64::from(self.constraint_id),
2114 ));
2115 facts.push((
2116 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2117 self.constraint_kind.raw(),
2118 ));
2119 facts.push((
2120 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2121 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2122 ));
2123 if let Some(mutation) = self.mutation {
2124 mutation.append_operation_facts(&mut facts);
2125 }
2126 if let Some(path) = self.value_path {
2127 for component in path.components {
2128 facts.push(constraint_value_path_fact(component));
2129 }
2130 }
2131 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2132 facts
2133 }
2134}
2135
2136fn append_accepted_schema_facts(
2138 facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2139 method: u8,
2140 fingerprint: [u8; 16],
2141) {
2142 facts.extend([
2143 (
2144 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2145 u64::from(method),
2146 ),
2147 (
2148 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2149 u64::from_be_bytes([
2150 fingerprint[0],
2151 fingerprint[1],
2152 fingerprint[2],
2153 fingerprint[3],
2154 fingerprint[4],
2155 fingerprint[5],
2156 fingerprint[6],
2157 fingerprint[7],
2158 ]),
2159 ),
2160 (
2161 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2162 u64::from_be_bytes([
2163 fingerprint[8],
2164 fingerprint[9],
2165 fingerprint[10],
2166 fingerprint[11],
2167 fingerprint[12],
2168 fingerprint[13],
2169 fingerprint[14],
2170 fingerprint[15],
2171 ]),
2172 ),
2173 ]);
2174}
2175
2176fn constraint_value_path_fact(
2177 component: ConstraintValuePathComponent,
2178) -> (diagnostic_code::DiagnosticFactTag, u64) {
2179 use diagnostic_code::DiagnosticFactTag;
2180 match component {
2181 ConstraintValuePathComponent::RootField { field_id } => {
2182 (DiagnosticFactTag::RootField, u64::from(field_id))
2183 }
2184 ConstraintValuePathComponent::RecordMember {
2185 composite_type_id,
2186 member_id,
2187 } => (
2188 DiagnosticFactTag::RecordMember,
2189 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2190 ),
2191 ConstraintValuePathComponent::TupleElement {
2192 composite_type_id,
2193 ordinal,
2194 } => (
2195 DiagnosticFactTag::TupleElement,
2196 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2197 ),
2198 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2199 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2200 }
2201 ConstraintValuePathComponent::EnumVariant {
2202 enum_type_id,
2203 variant_id,
2204 } => (
2205 DiagnosticFactTag::EnumVariant,
2206 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2207 ),
2208 ConstraintValuePathComponent::ListElement { index } => {
2209 (DiagnosticFactTag::ListElement, u64::from(index))
2210 }
2211 ConstraintValuePathComponent::SetElement { index } => {
2212 (DiagnosticFactTag::SetElement, u64::from(index))
2213 }
2214 ConstraintValuePathComponent::MapEntryKey { index } => {
2215 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2216 }
2217 ConstraintValuePathComponent::MapEntryValue { index } => {
2218 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2219 }
2220 }
2221}
2222
2223pub enum ErrorDetail {
2231 DiagnosticFacts(Box<DiagnosticFactDetail>),
2233 Executor(ExecutorErrorDetail),
2235 Store(StoreError),
2236 Query(QueryErrorDetail),
2237 Recovery(RecoveryErrorDetail),
2238 }
2241
2242pub enum ExecutorErrorDetail {
2244 MutationRequiredFieldMissing,
2246 MutationManagedTimestampRegression,
2248 MutationDatabaseOwnedFieldExplicit,
2250 MutationBatchEmpty,
2252 MutationBatchTooManyItems,
2254 MutationBatchStagedBytesExceeded,
2256 MutationBatchResultBytesExceeded,
2258 MutationBatchStoreMismatch,
2260 MutationBatchTooManyEntities,
2262 MutationBatchDuplicateKey,
2264 AcceptedRowConstraintProgramCorrupt,
2266}
2267
2268pub enum RecoveryErrorDetail {
2275 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2276
2277 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2278}
2279
2280#[derive(Clone, Copy, Eq, PartialEq)]
2282pub enum RecoveryFormatMarkerError {
2283 Magic,
2284 Checksum,
2285 State,
2286}
2287
2288impl RecoveryFormatMarkerError {
2289 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2290 match self {
2291 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2292 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2293 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2294 }
2295 }
2296}
2297
2298pub enum StoreError {
2306 NotFound,
2307
2308 Corrupt,
2309
2310 InvariantViolation,
2311
2312 SchemaDdlPublicationRaceLost,
2313
2314 SchemaDdlRewriteRequiresMigration,
2315
2316 SchemaMigration {
2317 reason: diagnostic_code::SchemaMigrationCode,
2318 },
2319
2320 SchemaRowLayoutVersionExhausted,
2321
2322 JournalMutationRevisionExhausted,
2323
2324 SchemaTransitionBudgetExceeded {
2325 resource: SchemaTransitionBudgetResource,
2326 },
2327
2328 SchemaGeneratedFieldAfterDdlField,
2330
2331 SchemaGeneratedConstraintActivationStale,
2333}
2334
2335pub enum QueryErrorDetail {
2342 ExactCountMetadataUnavailable,
2344
2345 NumericOverflow,
2346
2347 NumericNotRepresentable,
2348
2349 UnsupportedSqlFeature {
2350 feature: diagnostic_code::SqlFeatureCode,
2351 },
2352
2353 SqlLowering {
2354 reason: diagnostic_code::SqlLoweringCode,
2355 },
2356
2357 UnsupportedProjection {
2358 reason: diagnostic_code::QueryProjectionCode,
2359 },
2360
2361 UnknownAggregateTargetField,
2362
2363 QueryReadAdmission {
2364 reason: diagnostic_code::QueryReadAdmissionCode,
2365 },
2366
2367 SqlSurfaceMismatch {
2368 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2369 },
2370
2371 SqlWriteBoundary {
2372 boundary: diagnostic_code::SqlWriteBoundaryCode,
2373 },
2374
2375 SchemaDdlAdmission {
2376 error: SchemaDdlAdmissionError,
2377 },
2378
2379 StaleSchemaRevision,
2380}
2381
2382impl fmt::Display for QueryErrorDetail {
2383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2384 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2385 }
2386}
2387
2388impl std::error::Error for QueryErrorDetail {}
2389
2390#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2398pub enum SchemaTransitionBudgetResource {
2399 DeletionKeys,
2401 ProjectionEntries,
2403 ProjectionWorkUnits,
2405 SourceRows,
2407 SourceRowBytes,
2409 StagedRawBytes,
2411}
2412
2413#[derive(Clone, Copy, Eq, PartialEq)]
2422pub enum SchemaDdlAdmissionError {
2423 MissingExpectedSchemaVersion,
2424
2425 MissingNextSchemaVersion,
2426
2427 StaleExpectedSchemaVersion,
2428
2429 InvalidExpectedSchemaVersion,
2430
2431 InvalidNextSchemaVersion,
2432
2433 AcceptedSchemaChangeWithoutVersionBump,
2434
2435 EmptyVersionBump,
2436
2437 VersionGap,
2438
2439 VersionRollback,
2440
2441 FingerprintMethodMismatch,
2442
2443 UnsupportedTransitionClass,
2444
2445 PhysicalRunnerMissing,
2446
2447 ValidationFailed,
2448
2449 PublicationRaceLost,
2450
2451 InvalidAddColumnDefault,
2452
2453 InvalidAlterColumnDefault,
2454
2455 RowLayoutVersionExhausted,
2456
2457 GeneratedIndexDropRejected,
2458
2459 SchemaRewriteRequiresMigration,
2460
2461 SchemaTransitionBudgetExceeded {
2462 resource: SchemaTransitionBudgetResource,
2463 },
2464
2465 GeneratedFieldDefaultChangeRejected,
2466
2467 GeneratedFieldNullabilityChangeRejected,
2468}
2469
2470impl fmt::Display for SchemaDdlAdmissionError {
2471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2472 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2473 }
2474}
2475
2476impl std::error::Error for SchemaDdlAdmissionError {}
2477
2478impl fmt::Debug for ErrorDetail {
2479 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2480 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2481 }
2482}
2483
2484impl fmt::Debug for ExecutorErrorDetail {
2485 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2486 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2487 }
2488}
2489
2490impl fmt::Debug for StoreError {
2491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2492 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2493 }
2494}
2495
2496impl fmt::Debug for QueryErrorDetail {
2497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2498 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2499 }
2500}
2501
2502impl fmt::Debug for RecoveryErrorDetail {
2503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2504 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2505 }
2506}
2507
2508impl fmt::Debug for RecoveryFormatMarkerError {
2509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2510 fmt_compact_diagnostic(
2511 f,
2512 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2513 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2514 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2515 }),
2516 )
2517 }
2518}
2519
2520impl fmt::Debug for SchemaDdlAdmissionError {
2521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2522 fmt_compact_diagnostic(
2523 f,
2524 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2525 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2526 reason: self.diagnostic_code(),
2527 }),
2528 )
2529 }
2530}
2531
2532fn fmt_compact_diagnostic(
2533 f: &mut fmt::Formatter<'_>,
2534 code: diagnostic_code::DiagnosticCode,
2535 detail: Option<diagnostic_code::DiagnosticDetail>,
2536) -> fmt::Result {
2537 write!(
2538 f,
2539 "{}",
2540 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2541 )
2542}
2543
2544impl ErrorDetail {
2545 #[must_use]
2547 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2548 match self {
2549 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2550 Self::Executor(error) => error.diagnostic_code(),
2551 Self::Store(error) => error.diagnostic_code(),
2552 Self::Query(error) => error.diagnostic_code(),
2553 Self::Recovery(error) => error.diagnostic_code(),
2554 }
2555 }
2556
2557 #[must_use]
2559 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2560 match self {
2561 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2562 Self::Executor(error) => error.diagnostic_detail(),
2563 Self::Store(error) => error.diagnostic_detail(),
2564 Self::Query(error) => error.diagnostic_detail(),
2565 Self::Recovery(error) => error.diagnostic_detail(),
2566 }
2567 }
2568
2569 #[must_use]
2571 #[cold]
2572 #[inline(never)]
2573 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2574 match self {
2575 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2576 Self::Executor(error) => error.diagnostic_facts(),
2577 Self::Query(error) => error.diagnostic_facts(),
2578 Self::Recovery(error) => error.diagnostic_facts(),
2579 Self::Store(_) => Vec::new(),
2580 }
2581 }
2582}
2583
2584impl ExecutorErrorDetail {
2585 #[must_use]
2587 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2588 match self {
2589 Self::MutationRequiredFieldMissing
2590 | Self::MutationDatabaseOwnedFieldExplicit
2591 | Self::MutationBatchEmpty
2592 | Self::MutationBatchTooManyItems
2593 | Self::MutationBatchTooManyEntities
2594 | Self::MutationBatchStagedBytesExceeded
2595 | Self::MutationBatchResultBytesExceeded => {
2596 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2597 }
2598 Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2599 diagnostic_code::DiagnosticCode::RuntimeConflict
2600 }
2601 Self::MutationManagedTimestampRegression => {
2602 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2603 }
2604 Self::AcceptedRowConstraintProgramCorrupt => {
2605 diagnostic_code::DiagnosticCode::RuntimeCorruption
2606 }
2607 }
2608 }
2609
2610 #[must_use]
2612 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2613 match self {
2614 Self::MutationRequiredFieldMissing => {
2615 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2616 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2617 })
2618 }
2619 Self::MutationDatabaseOwnedFieldExplicit => {
2620 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2621 boundary:
2622 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2623 })
2624 }
2625 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2626 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2627 }),
2628 Self::MutationBatchTooManyItems => {
2629 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2630 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2631 })
2632 }
2633 Self::MutationBatchStagedBytesExceeded => {
2634 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2635 boundary:
2636 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2637 })
2638 }
2639 Self::MutationBatchResultBytesExceeded => {
2640 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2641 boundary:
2642 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2643 })
2644 }
2645 Self::MutationBatchStoreMismatch => {
2646 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2647 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2648 })
2649 }
2650 Self::MutationBatchTooManyEntities => {
2651 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2652 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2653 })
2654 }
2655 Self::MutationBatchDuplicateKey => {
2656 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2657 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2658 })
2659 }
2660 Self::MutationManagedTimestampRegression => {
2661 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2662 boundary:
2663 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2664 })
2665 }
2666 Self::AcceptedRowConstraintProgramCorrupt => {
2667 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2668 boundary:
2669 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2670 })
2671 }
2672 }
2673 }
2674
2675 #[must_use]
2677 #[cold]
2678 #[inline(never)]
2679 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2680 Vec::new()
2681 }
2682}
2683
2684impl RecoveryErrorDetail {
2685 #[must_use]
2687 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2688 match self {
2689 Self::UnsupportedFormatVersion { .. } => {
2690 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2691 }
2692 Self::MalformedFormatMarker { .. } => {
2693 diagnostic_code::DiagnosticCode::RuntimeCorruption
2694 }
2695 }
2696 }
2697
2698 #[must_use]
2700 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2701 let kind = match self {
2702 Self::UnsupportedFormatVersion { .. } => {
2703 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2704 }
2705 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2706 };
2707
2708 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2709 }
2710
2711 #[must_use]
2713 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2714 match self {
2715 Self::UnsupportedFormatVersion { found, required } => {
2716 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2717 facts.push((
2718 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2719 u64::from(*required),
2720 ));
2721 if let Some(found) = found {
2722 facts.push((
2723 diagnostic_code::DiagnosticFactTag::ActualVersion,
2724 u64::from(*found),
2725 ));
2726 }
2727 facts
2728 }
2729 Self::MalformedFormatMarker { reason } => vec![(
2730 diagnostic_code::DiagnosticFactTag::DecodeReason,
2731 reason.diagnostic_decode_reason().raw(),
2732 )],
2733 }
2734 }
2735}
2736
2737impl StoreError {
2738 #[must_use]
2740 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2741 match self {
2742 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2743 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2744 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2745 Self::SchemaDdlPublicationRaceLost
2746 | Self::SchemaDdlRewriteRequiresMigration
2747 | Self::SchemaRowLayoutVersionExhausted
2748 | Self::SchemaTransitionBudgetExceeded { .. } => {
2749 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2750 }
2751 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2752 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2753 }
2754 Self::SchemaGeneratedConstraintActivationStale => {
2755 diagnostic_code::DiagnosticCode::RuntimeConflict
2756 }
2757 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2758 }
2759 }
2760
2761 #[must_use]
2763 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2764 match self {
2765 Self::SchemaDdlPublicationRaceLost => {
2766 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2767 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2768 })
2769 }
2770 Self::SchemaDdlRewriteRequiresMigration => {
2771 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2772 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2773 })
2774 }
2775 Self::SchemaMigration { reason } => {
2776 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2777 }
2778 Self::SchemaRowLayoutVersionExhausted => {
2779 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2780 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2781 })
2782 }
2783 Self::JournalMutationRevisionExhausted => {
2784 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2785 boundary:
2786 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2787 })
2788 }
2789 Self::SchemaTransitionBudgetExceeded { .. } => {
2790 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2791 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2792 })
2793 }
2794 Self::SchemaGeneratedFieldAfterDdlField => {
2795 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2796 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2797 })
2798 }
2799 Self::SchemaGeneratedConstraintActivationStale => {
2800 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2801 boundary:
2802 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2803 })
2804 }
2805 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2806 }
2807 }
2808}
2809
2810impl QueryErrorDetail {
2811 #[must_use]
2813 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2814 match self {
2815 Self::ExactCountMetadataUnavailable => {
2816 diagnostic_code::DiagnosticCode::QueryExactCountMetadataUnavailable
2817 }
2818 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2819 Self::NumericNotRepresentable => {
2820 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2821 }
2822 Self::UnsupportedSqlFeature { .. } => {
2823 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2824 }
2825 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2826 Self::UnsupportedProjection { .. } => {
2827 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2828 }
2829 Self::UnknownAggregateTargetField => {
2830 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2831 }
2832 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2833 Self::SqlSurfaceMismatch { .. } => {
2834 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2835 }
2836 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2837 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2838 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2839 }
2840 }
2841
2842 #[must_use]
2844 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2845 match self {
2846 Self::UnsupportedSqlFeature { feature } => {
2847 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2848 }
2849 Self::SqlLowering { reason } => {
2850 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2851 }
2852 Self::UnsupportedProjection { reason } => {
2853 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2854 }
2855 Self::QueryReadAdmission { reason } => {
2856 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2857 }
2858 Self::SqlSurfaceMismatch { mismatch } => {
2859 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2860 mismatch: *mismatch,
2861 })
2862 }
2863 Self::SqlWriteBoundary { boundary } => {
2864 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2865 boundary: *boundary,
2866 })
2867 }
2868 Self::SchemaDdlAdmission { error } => {
2869 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2870 reason: error.diagnostic_code(),
2871 })
2872 }
2873 Self::ExactCountMetadataUnavailable
2874 | Self::NumericOverflow
2875 | Self::NumericNotRepresentable
2876 | Self::UnknownAggregateTargetField
2877 | Self::StaleSchemaRevision => None,
2878 }
2879 }
2880
2881 #[must_use]
2883 #[cold]
2884 #[inline(never)]
2885 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2886 Vec::new()
2887 }
2888}
2889
2890impl SchemaDdlAdmissionError {
2891 #[must_use]
2893 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2894 match self {
2895 Self::MissingExpectedSchemaVersion => {
2896 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2897 }
2898 Self::MissingNextSchemaVersion => {
2899 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2900 }
2901 Self::StaleExpectedSchemaVersion => {
2902 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2903 }
2904 Self::InvalidExpectedSchemaVersion => {
2905 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2906 }
2907 Self::InvalidNextSchemaVersion => {
2908 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2909 }
2910 Self::AcceptedSchemaChangeWithoutVersionBump => {
2911 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2912 }
2913 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2914 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2915 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2916 Self::FingerprintMethodMismatch => {
2917 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2918 }
2919 Self::UnsupportedTransitionClass => {
2920 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2921 }
2922 Self::PhysicalRunnerMissing => {
2923 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2924 }
2925 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2926 Self::PublicationRaceLost => {
2927 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2928 }
2929 Self::InvalidAddColumnDefault => {
2930 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2931 }
2932 Self::InvalidAlterColumnDefault => {
2933 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2934 }
2935 Self::GeneratedIndexDropRejected => {
2936 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2937 }
2938 Self::SchemaRewriteRequiresMigration => {
2939 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2940 }
2941 Self::SchemaTransitionBudgetExceeded { .. } => {
2942 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2943 }
2944 Self::GeneratedFieldDefaultChangeRejected => {
2945 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2946 }
2947 Self::GeneratedFieldNullabilityChangeRejected => {
2948 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2949 }
2950 Self::RowLayoutVersionExhausted => {
2951 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2952 }
2953 }
2954 }
2955}
2956
2957#[repr(u8)]
2964#[derive(Clone, Copy, Eq, PartialEq)]
2965pub enum ErrorClass {
2966 Corruption,
2967 IncompatiblePersistedFormat,
2968 NotFound,
2969 Internal,
2970 Conflict,
2971 Unsupported,
2972 InvariantViolation,
2973}
2974
2975impl ErrorClass {
2976 #[must_use]
2978 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2979 match self {
2980 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2981 diagnostic_code::DiagnosticCode::StoreCorruption
2982 }
2983 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2984 Self::IncompatiblePersistedFormat => {
2985 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2986 }
2987 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2988 diagnostic_code::DiagnosticCode::StoreNotFound
2989 }
2990 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2991 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2992 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2993 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2994 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2995 }
2996 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2997 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2998 diagnostic_code::DiagnosticCode::StoreInvariantViolation
2999 }
3000 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3001 }
3002 }
3003}
3004
3005impl fmt::Debug for ErrorClass {
3006 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3007 write!(f, "{}", *self as u8)
3008 }
3009}
3010
3011#[repr(u8)]
3018#[derive(Clone, Copy, Eq, PartialEq)]
3019pub enum ErrorOrigin {
3020 Serialize,
3021 Store,
3022 Index,
3023 Identity,
3024 Query,
3025 Planner,
3026 Cursor,
3027 Recovery,
3028 Response,
3029 Executor,
3030 Interface,
3031}
3032
3033impl ErrorOrigin {
3034 #[must_use]
3036 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3037 match self {
3038 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3039 Self::Store => diagnostic_code::ErrorOrigin::Store,
3040 Self::Index => diagnostic_code::ErrorOrigin::Index,
3041 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3042 Self::Query => diagnostic_code::ErrorOrigin::Query,
3043 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3044 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3045 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3046 Self::Response => diagnostic_code::ErrorOrigin::Response,
3047 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3048 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3049 }
3050 }
3051}
3052
3053impl fmt::Debug for ErrorOrigin {
3054 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3055 write!(f, "{}", *self as u8)
3056 }
3057}