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)]
134pub(crate) struct MutationDiagnosticContext {
135 entity_tag: u64,
136 operation: diagnostic_code::DiagnosticMutationOperation,
137 batch_position: Option<u32>,
138}
139
140impl MutationDiagnosticContext {
141 #[must_use]
143 pub(crate) const fn new(
144 entity_tag: u64,
145 operation: diagnostic_code::DiagnosticMutationOperation,
146 batch_position: u32,
147 ) -> Self {
148 Self {
149 entity_tag,
150 operation,
151 batch_position: Some(batch_position),
152 }
153 }
154
155 #[must_use]
157 pub(crate) const fn operation_only(
158 entity_tag: u64,
159 operation: diagnostic_code::DiagnosticMutationOperation,
160 ) -> Self {
161 Self {
162 entity_tag,
163 operation,
164 batch_position: None,
165 }
166 }
167
168 fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
169 let mut facts = Vec::with_capacity(
170 2 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
171 );
172 facts.push((
173 diagnostic_code::DiagnosticFactTag::EntityTag,
174 self.entity_tag,
175 ));
176 if let Some(field_id) = field_id {
177 facts.push((
178 diagnostic_code::DiagnosticFactTag::FieldId,
179 u64::from(field_id),
180 ));
181 }
182 facts.push((
183 diagnostic_code::DiagnosticFactTag::MutationOperation,
184 self.operation.raw(),
185 ));
186 if let Some(batch_position) = self.batch_position {
187 facts.push((
188 diagnostic_code::DiagnosticFactTag::BatchPosition,
189 u64::from(batch_position),
190 ));
191 }
192 facts
193 }
194
195 #[must_use]
196 pub(crate) const fn entity_tag(self) -> u64 {
197 self.entity_tag
198 }
199
200 fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
201 facts.push((
202 diagnostic_code::DiagnosticFactTag::MutationOperation,
203 self.operation.raw(),
204 ));
205 if let Some(batch_position) = self.batch_position {
206 facts.push((
207 diagnostic_code::DiagnosticFactTag::BatchPosition,
208 u64::from(batch_position),
209 ));
210 }
211 }
212}
213
214pub struct DiagnosticFactDetail {
216 diagnostic: diagnostic_code::Diagnostic,
217 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
218}
219
220pub struct InternalError {
228 pub(crate) class: ErrorClass,
229 pub(crate) origin: ErrorOrigin,
230
231 pub(crate) detail: Option<ErrorDetail>,
234}
235
236#[expect(
237 clippy::missing_const_for_fn,
238 reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
239)]
240impl InternalError {
241 #[must_use]
245 #[cold]
246 #[inline(never)]
247 pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
248 let detail = match (class, origin) {
249 (ErrorClass::Corruption, ErrorOrigin::Store) => {
250 Some(ErrorDetail::Store(StoreError::Corrupt))
251 }
252 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
253 Some(ErrorDetail::Store(StoreError::InvariantViolation))
254 }
255 _ => None,
256 };
257
258 Self {
259 class,
260 origin,
261 detail,
262 }
263 }
264
265 #[must_use]
267 pub const fn class(&self) -> ErrorClass {
268 self.class
269 }
270
271 #[must_use]
273 pub const fn origin(&self) -> ErrorOrigin {
274 self.origin
275 }
276
277 #[must_use]
279 pub const fn message(&self) -> &'static str {
280 compact_message_for(self.class, self.origin)
281 }
282
283 #[must_use]
285 pub const fn detail(&self) -> Option<&ErrorDetail> {
286 self.detail.as_ref()
287 }
288
289 #[must_use]
291 pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
292 diagnostic_code::Diagnostic::new(
293 self.diagnostic_code(),
294 self.origin.diagnostic_origin(),
295 self.detail
296 .as_ref()
297 .and_then(ErrorDetail::diagnostic_detail),
298 )
299 }
300
301 #[must_use]
303 #[cold]
304 #[inline(never)]
305 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
306 self.detail
307 .as_ref()
308 .map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
309 }
310
311 #[must_use]
313 pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
314 self.detail.as_ref().map_or_else(
315 || self.class.diagnostic_code(self.origin),
316 ErrorDetail::diagnostic_code,
317 )
318 }
319
320 #[must_use]
322 pub fn into_message(self) -> String {
323 self.message().to_string()
324 }
325
326 #[cold]
328 #[inline(never)]
329 pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
330 Self::new(class, origin)
331 }
332
333 #[cold]
334 #[inline(never)]
335 fn with_diagnostic_facts(
336 class: ErrorClass,
337 origin: ErrorOrigin,
338 detail: Option<diagnostic_code::DiagnosticDetail>,
339 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
340 ) -> Self {
341 let code = match detail {
342 Some(detail) => detail.diagnostic_code(),
343 None => class.diagnostic_code(origin),
344 };
345 let diagnostic = diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), detail);
346 if diagnostic_code::validate_known_diagnostic_fact_schema(
347 diagnostic.error_code(),
348 facts.as_slice(),
349 )
350 .is_err()
351 {
352 return Self::new(ErrorClass::InvariantViolation, origin);
353 }
354 Self {
355 class,
356 origin,
357 detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
358 DiagnosticFactDetail { diagnostic, facts },
359 ))),
360 }
361 }
362
363 #[cold]
364 #[inline(never)]
365 fn mutation_boundary_with_facts(
366 class: ErrorClass,
367 boundary: diagnostic_code::RuntimeBoundaryCode,
368 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
369 ) -> Self {
370 Self::with_diagnostic_facts(
371 class,
372 ErrorOrigin::Executor,
373 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
374 facts,
375 )
376 }
377
378 #[cold]
379 #[inline(never)]
380 fn exact_key_batch_boundary_with_facts(
381 boundary: diagnostic_code::RuntimeBoundaryCode,
382 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
383 ) -> Self {
384 Self::with_diagnostic_facts(
385 ErrorClass::Unsupported,
386 ErrorOrigin::Query,
387 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
388 facts,
389 )
390 }
391
392 pub(crate) fn sql_query_entity_not_found() -> Self {
394 Self::with_diagnostic_facts(
395 ErrorClass::NotFound,
396 ErrorOrigin::Interface,
397 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
398 boundary: diagnostic_code::RuntimeBoundaryCode::SqlQueryEntityNotFound,
399 }),
400 Vec::new(),
401 )
402 }
403
404 #[cold]
406 #[inline(never)]
407 pub(crate) fn execution_budget_exceeded(
408 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
409 limit: u64,
410 observed: u64,
411 scope: diagnostic_code::DiagnosticExecutionBudgetScope,
412 lane: diagnostic_code::DiagnosticExecutionLane,
413 normalized_shape_fingerprint_prefix: u64,
414 ) -> Self {
415 Self::with_diagnostic_facts(
416 ErrorClass::Unsupported,
417 ErrorOrigin::Executor,
418 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
419 boundary: diagnostic_code::RuntimeBoundaryCode::ExecutionBudgetExceeded,
420 }),
421 vec![
422 (
423 diagnostic_code::DiagnosticFactTag::BudgetResource,
424 resource.raw(),
425 ),
426 (diagnostic_code::DiagnosticFactTag::Limit, limit),
427 (diagnostic_code::DiagnosticFactTag::Actual, observed),
428 (
429 diagnostic_code::DiagnosticFactTag::ExecutionBudgetScope,
430 scope.raw(),
431 ),
432 (
433 diagnostic_code::DiagnosticFactTag::ExecutionLane,
434 lane.raw(),
435 ),
436 (
437 diagnostic_code::DiagnosticFactTag::QueryShapeFingerprintPrefix,
438 normalized_shape_fingerprint_prefix,
439 ),
440 ],
441 )
442 }
443
444 #[cold]
446 #[inline(never)]
447 pub(crate) fn page_unit_too_large(
448 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
449 limit: u64,
450 attempted: u64,
451 ) -> Self {
452 Self::with_diagnostic_facts(
453 ErrorClass::Unsupported,
454 ErrorOrigin::Executor,
455 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
456 boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
457 }),
458 vec![
459 (
460 diagnostic_code::DiagnosticFactTag::BudgetResource,
461 resource.raw(),
462 ),
463 (diagnostic_code::DiagnosticFactTag::Limit, limit),
464 (diagnostic_code::DiagnosticFactTag::Actual, attempted),
465 ],
466 )
467 }
468
469 #[cold]
474 #[inline(never)]
475 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
476 match self.detail {
477 Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
478 self.class,
479 origin,
480 detail.diagnostic.detail().copied(),
481 detail.facts,
482 ),
483 _ => Self::classified(self.class, origin),
484 }
485 }
486
487 #[cold]
489 #[inline(never)]
490 pub(crate) fn index_invariant() -> Self {
491 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
492 }
493
494 pub(crate) fn index_key_field_count_exceeds_max(
496 entity_tag: u64,
497 physical_generation: u64,
498 field_count: usize,
499 max_fields: usize,
500 ) -> Self {
501 Self::with_diagnostic_facts(
502 ErrorClass::InvariantViolation,
503 ErrorOrigin::Index,
504 None,
505 vec![
506 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
507 (
508 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
509 physical_generation,
510 ),
511 (
512 diagnostic_code::DiagnosticFactTag::ComponentKind,
513 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
514 ),
515 (
516 diagnostic_code::DiagnosticFactTag::ActualArity,
517 field_count as u64,
518 ),
519 (
520 diagnostic_code::DiagnosticFactTag::Maximum,
521 max_fields as u64,
522 ),
523 ],
524 )
525 }
526
527 pub(crate) fn index_expression_source_type_mismatch(
529 _index_name: &str,
530 _expression: impl Sized,
531 _expected: impl Sized,
532 _source_label: &str,
533 ) -> Self {
534 Self::index_invariant()
535 }
536
537 #[cold]
540 #[inline(never)]
541 pub(crate) fn planner_executor_invariant() -> Self {
542 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
543 }
544
545 #[cold]
548 #[inline(never)]
549 pub(crate) fn query_executor_invariant() -> Self {
550 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
551 }
552
553 #[cold]
556 #[inline(never)]
557 pub(crate) fn cursor_executor_invariant() -> Self {
558 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
559 }
560
561 #[cold]
563 #[inline(never)]
564 pub(crate) fn executor_invariant() -> Self {
565 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
566 }
567
568 #[cold]
570 #[inline(never)]
571 pub(crate) fn executor_internal() -> Self {
572 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
573 }
574
575 #[cold]
577 #[inline(never)]
578 pub(crate) fn executor_unsupported() -> Self {
579 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
580 }
581
582 #[cold]
584 #[inline(never)]
585 pub(crate) fn mutation_database_owned_field_explicit(
586 context: MutationDiagnosticContext,
587 field_id: u32,
588 ) -> Self {
589 Self::mutation_boundary_with_facts(
590 ErrorClass::Unsupported,
591 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
592 context.facts(Some(field_id)),
593 )
594 }
595
596 #[must_use]
598 #[cold]
599 #[inline(never)]
600 pub(crate) fn mutation_required_field_missing(
601 context: MutationDiagnosticContext,
602 field_id: u32,
603 ) -> Self {
604 Self::mutation_boundary_with_facts(
605 ErrorClass::Unsupported,
606 diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
607 context.facts(Some(field_id)),
608 )
609 }
610
611 #[must_use]
613 #[cold]
614 #[inline(never)]
615 pub(crate) fn mutation_managed_timestamp_regression(
616 context: MutationDiagnosticContext,
617 ) -> Self {
618 Self::mutation_boundary_with_facts(
619 ErrorClass::InvariantViolation,
620 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
621 context.facts(None),
622 )
623 }
624
625 pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
627 Self::mutation_boundary_with_facts(
628 ErrorClass::InvariantViolation,
629 diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
630 context.facts(),
631 )
632 }
633
634 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
636 Self {
637 class: ErrorClass::Corruption,
638 origin: ErrorOrigin::Executor,
639 detail: Some(ErrorDetail::Executor(
640 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
641 )),
642 }
643 }
644
645 pub(crate) fn mutation_constraint_activation_write_blocked(
647 context: AcceptedConstraintFactContext,
648 ) -> Self {
649 Self::mutation_boundary_with_facts(
650 ErrorClass::Conflict,
651 diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
652 context.facts(),
653 )
654 }
655
656 pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
658 Self::executor_invariant()
659 }
660
661 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
663 Self::query_executor_invariant()
664 }
665
666 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
668 Self::query_executor_invariant()
669 }
670
671 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
673 Self::query_executor_invariant()
674 }
675
676 pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
678 Self::query_executor_invariant()
679 }
680
681 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
683 Self::query_executor_invariant()
684 }
685
686 pub(crate) fn index_range_limit_spec_required() -> Self {
688 Self::query_executor_invariant()
689 }
690
691 #[cold]
693 #[inline(never)]
694 pub(crate) fn mutation_atomic_save_duplicate_key(
695 entity_tag: u64,
696 first_position: u32,
697 duplicate_position: u32,
698 ) -> Self {
699 Self::mutation_boundary_with_facts(
700 ErrorClass::Conflict,
701 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
702 vec![
703 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
704 (
705 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
706 u64::from(first_position),
707 ),
708 (
709 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
710 u64::from(duplicate_position),
711 ),
712 ],
713 )
714 }
715
716 #[cold]
718 #[inline(never)]
719 pub(crate) fn mutation_batch_empty() -> Self {
720 Self::mutation_boundary_with_facts(
721 ErrorClass::Unsupported,
722 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
723 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
724 )
725 }
726
727 #[cold]
729 #[inline(never)]
730 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
731 Self::mutation_boundary_with_facts(
732 ErrorClass::Unsupported,
733 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
734 vec![
735 (
736 diagnostic_code::DiagnosticFactTag::ActualCount,
737 actual_count as u64,
738 ),
739 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
740 ],
741 )
742 }
743
744 #[cold]
746 #[inline(never)]
747 pub(crate) fn mutation_batch_staged_bytes_exceeded(
748 actual_bytes: Option<usize>,
749 limit: usize,
750 ) -> Self {
751 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
752 if let Some(actual_bytes) = actual_bytes {
753 facts.push((
754 diagnostic_code::DiagnosticFactTag::ActualLength,
755 actual_bytes as u64,
756 ));
757 }
758 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
759 Self::mutation_boundary_with_facts(
760 ErrorClass::Unsupported,
761 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
762 facts,
763 )
764 }
765
766 #[cold]
768 #[inline(never)]
769 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
770 Self::mutation_boundary_with_facts(
771 ErrorClass::Unsupported,
772 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
773 vec![
774 (
775 diagnostic_code::DiagnosticFactTag::ActualLength,
776 actual_bytes as u64,
777 ),
778 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
779 ],
780 )
781 }
782
783 #[cold]
785 #[inline(never)]
786 pub(crate) fn mutation_batch_commit_work_exceeded(
787 actual_units: Option<usize>,
788 limit: usize,
789 ) -> Self {
790 let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
791 if let Some(actual_units) = actual_units {
792 facts.push((
793 diagnostic_code::DiagnosticFactTag::ActualCount,
794 actual_units as u64,
795 ));
796 }
797 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
798 Self::mutation_boundary_with_facts(
799 ErrorClass::Unsupported,
800 diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
801 facts,
802 )
803 }
804
805 #[cold]
807 #[inline(never)]
808 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
809 Self::exact_key_batch_boundary_with_facts(
810 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
811 vec![
812 (
813 diagnostic_code::DiagnosticFactTag::ActualCount,
814 actual_count as u64,
815 ),
816 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
817 ],
818 )
819 }
820
821 #[cold]
823 #[inline(never)]
824 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
825 Self::exact_key_batch_bytes_exceeded(
826 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
827 actual_bytes,
828 limit,
829 )
830 }
831
832 #[cold]
834 #[inline(never)]
835 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
836 Self::exact_key_batch_bytes_exceeded(
837 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
838 actual_bytes,
839 limit,
840 )
841 }
842
843 #[cold]
845 #[inline(never)]
846 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
847 Self::exact_key_batch_bytes_exceeded(
848 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
849 actual_bytes,
850 limit,
851 )
852 }
853
854 #[cold]
855 #[inline(never)]
856 fn exact_key_batch_bytes_exceeded(
857 boundary: diagnostic_code::RuntimeBoundaryCode,
858 actual_bytes: usize,
859 limit: usize,
860 ) -> Self {
861 Self::exact_key_batch_boundary_with_facts(
862 boundary,
863 vec![
864 (
865 diagnostic_code::DiagnosticFactTag::ActualLength,
866 actual_bytes as u64,
867 ),
868 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
869 ],
870 )
871 }
872
873 #[cold]
875 #[inline(never)]
876 pub(crate) fn mutation_batch_entity_mismatch(
877 batch_position: u32,
878 expected_entity_tag: u64,
879 actual_entity_tag: u64,
880 ) -> Self {
881 Self::mutation_boundary_with_facts(
882 ErrorClass::Conflict,
883 diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
884 vec![
885 (
886 diagnostic_code::DiagnosticFactTag::BatchPosition,
887 u64::from(batch_position),
888 ),
889 (
890 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
891 expected_entity_tag,
892 ),
893 (
894 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
895 actual_entity_tag,
896 ),
897 ],
898 )
899 }
900
901 pub(crate) fn mutation_index_store_generation_changed(
903 _expected_generation: u64,
904 _observed_generation: u64,
905 ) -> Self {
906 Self::executor_invariant()
907 }
908
909 #[cold]
911 #[inline(never)]
912 pub(crate) fn planner_invariant() -> Self {
913 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
914 }
915
916 pub(crate) fn query_invalid_logical_plan() -> Self {
918 Self::planner_invariant()
919 }
920
921 pub(crate) fn store_invariant() -> Self {
923 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
924 }
925
926 #[cold]
928 #[inline(never)]
929 pub(crate) fn store_internal() -> Self {
930 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
931 }
932
933 pub(crate) fn commit_memory_id_unconfigured() -> Self {
935 Self::store_internal()
936 }
937
938 pub(crate) fn commit_store_uninitialized() -> Self {
940 Self::store_invariant()
941 }
942
943 pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
945 Self::with_diagnostic_facts(
946 ErrorClass::Internal,
947 ErrorOrigin::Store,
948 None,
949 vec![
950 (
951 diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
952 u64::from(cached_id),
953 ),
954 (
955 diagnostic_code::DiagnosticFactTag::ActualMemoryId,
956 u64::from(configured_id),
957 ),
958 ],
959 )
960 }
961
962 pub(crate) fn commit_memory_stable_key_mismatch(
964 _cached_key: &str,
965 _configured_key: &str,
966 ) -> Self {
967 Self::store_internal()
968 }
969
970 pub(crate) fn database_incarnation_generation_failed() -> Self {
972 Self::store_internal()
973 }
974
975 pub(crate) fn database_incarnation_invalid() -> Self {
977 Self::store_corruption()
978 }
979
980 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
982 Self {
983 class: ErrorClass::IncompatiblePersistedFormat,
984 origin: ErrorOrigin::Recovery,
985 detail: Some(ErrorDetail::Recovery(
986 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
987 )),
988 }
989 }
990
991 pub(crate) fn recovery_malformed_database_format_marker(
993 reason: RecoveryFormatMarkerError,
994 ) -> Self {
995 Self {
996 class: ErrorClass::Corruption,
997 origin: ErrorOrigin::Recovery,
998 detail: Some(ErrorDetail::Recovery(
999 RecoveryErrorDetail::MalformedFormatMarker { reason },
1000 )),
1001 }
1002 }
1003
1004 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1006 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1007 }
1008
1009 pub(crate) fn recovery_pending() -> Self {
1011 Self::with_diagnostic_facts(
1012 ErrorClass::Conflict,
1013 ErrorOrigin::Recovery,
1014 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1015 boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1016 }),
1017 Vec::new(),
1018 )
1019 }
1020
1021 pub(crate) fn startup_control_corruption() -> Self {
1023 Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1024 }
1025
1026 pub(crate) fn commit_control_memory_growth_failed() -> Self {
1028 Self::store_internal()
1029 }
1030
1031 #[cfg(not(test))]
1033 pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1034 Self::store_internal()
1035 }
1036
1037 pub(crate) fn recovery_effect_verification_failed() -> Self {
1039 Self::store_corruption()
1040 }
1041
1042 #[cold]
1044 #[inline(never)]
1045 pub(crate) fn index_internal() -> Self {
1046 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1047 }
1048
1049 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1051 Self::index_internal()
1052 }
1053
1054 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1056 Self::index_internal()
1057 }
1058
1059 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1061 Self::index_internal()
1062 }
1063
1064 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1066 Self::index_internal()
1067 }
1068
1069 #[cfg(test)]
1071 pub(crate) fn query_internal() -> Self {
1072 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1073 }
1074
1075 #[cold]
1077 #[inline(never)]
1078 pub(crate) fn query_unsupported() -> Self {
1079 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1080 }
1081
1082 #[cold]
1085 #[inline(never)]
1086 pub(crate) fn query_stale_accepted_schema_revision(
1087 expected_revision: u64,
1088 current_revision: Option<u64>,
1089 ) -> Self {
1090 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1091 facts.push((
1092 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1093 expected_revision,
1094 ));
1095 if let Some(current_revision) = current_revision {
1096 facts.push((
1097 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1098 current_revision,
1099 ));
1100 }
1101 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1102 }
1103
1104 #[cold]
1106 #[inline(never)]
1107 #[cfg(feature = "sql")]
1108 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1109 Self {
1110 class: ErrorClass::Unsupported,
1111 origin: ErrorOrigin::Query,
1112 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1113 error,
1114 })),
1115 }
1116 }
1117
1118 #[cold]
1120 #[inline(never)]
1121 pub(crate) fn query_numeric_overflow() -> Self {
1122 Self {
1123 class: ErrorClass::Unsupported,
1124 origin: ErrorOrigin::Query,
1125 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1126 }
1127 }
1128
1129 #[cold]
1132 #[inline(never)]
1133 pub(crate) fn query_numeric_not_representable() -> Self {
1134 Self {
1135 class: ErrorClass::Unsupported,
1136 origin: ErrorOrigin::Query,
1137 detail: Some(ErrorDetail::Query(
1138 QueryErrorDetail::NumericNotRepresentable,
1139 )),
1140 }
1141 }
1142
1143 #[cold]
1145 #[inline(never)]
1146 pub(crate) fn serialize_internal() -> Self {
1147 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1148 }
1149
1150 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1152 Self::persisted_row_encode_internal()
1153 }
1154
1155 pub(crate) fn persisted_row_encode_internal() -> Self {
1157 Self::serialize_internal()
1158 }
1159
1160 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1162 Self::persisted_row_encode_internal()
1163 }
1164
1165 #[cold]
1167 #[inline(never)]
1168 pub(crate) fn store_corruption() -> Self {
1169 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1170 }
1171
1172 pub(crate) fn commit_corruption() -> Self {
1174 Self::store_corruption()
1175 }
1176
1177 pub(crate) fn commit_component_corruption() -> Self {
1179 Self::commit_corruption()
1180 }
1181
1182 pub(crate) fn commit_id_generation_failed() -> Self {
1184 Self::store_internal()
1185 }
1186
1187 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1189 Self::store_unsupported()
1190 }
1191
1192 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1194 Self::with_diagnostic_facts(
1195 ErrorClass::Corruption,
1196 ErrorOrigin::Store,
1197 None,
1198 vec![
1199 (
1200 diagnostic_code::DiagnosticFactTag::ComponentKind,
1201 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1202 ),
1203 (
1204 diagnostic_code::DiagnosticFactTag::ActualLength,
1205 actual_length as u64,
1206 ),
1207 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1208 ],
1209 )
1210 }
1211
1212 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1214 Self::commit_corruption()
1215 }
1216
1217 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1219 Self::store_unsupported()
1220 }
1221
1222 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1224 Self::store_unsupported()
1225 }
1226
1227 #[cold]
1229 #[inline(never)]
1230 pub(crate) fn index_corruption() -> Self {
1231 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1232 }
1233
1234 pub(crate) fn index_unique_validation_corruption() -> Self {
1236 Self::index_plan_index_corruption()
1237 }
1238
1239 pub(crate) fn structural_index_entry_corruption() -> Self {
1241 Self::index_plan_index_corruption()
1242 }
1243
1244 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1246 Self::index_invariant()
1247 }
1248
1249 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1251 Self::index_plan_serialize_corruption()
1252 }
1253
1254 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1256 Self::index_plan_serialize_corruption()
1257 }
1258
1259 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1261 Self::index_plan_serialize_corruption()
1262 }
1263
1264 pub(crate) fn index_unique_validation_row_required() -> Self {
1266 Self::index_plan_store_corruption()
1267 }
1268
1269 pub(crate) fn index_only_predicate_component_required() -> Self {
1271 Self::index_invariant()
1272 }
1273
1274 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1276 Self::index_invariant()
1277 }
1278
1279 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1281 Self::index_invariant()
1282 }
1283
1284 pub(crate) fn index_scan_key_corrupted_during(
1286 _context: &'static str,
1287 _err: impl Sized,
1288 ) -> Self {
1289 Self::index_corruption()
1290 }
1291
1292 pub(crate) fn index_projection_component_required(
1294 _index_name: &str,
1295 _component_index: usize,
1296 ) -> Self {
1297 Self::index_invariant()
1298 }
1299
1300 pub(crate) fn index_entry_decode_failed() -> Self {
1302 Self::index_corruption()
1303 }
1304
1305 pub(crate) fn serialize_corruption() -> Self {
1307 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1308 }
1309
1310 pub(crate) fn persisted_row_decode_corruption() -> Self {
1312 Self::serialize_corruption()
1313 }
1314
1315 pub(crate) fn persisted_row_layout_outside_accepted_window(
1317 row_layout: u32,
1318 history_floor: u32,
1319 current_layout: u32,
1320 ) -> Self {
1321 Self::with_diagnostic_facts(
1322 ErrorClass::Corruption,
1323 ErrorOrigin::Serialize,
1324 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1325 boundary:
1326 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1327 }),
1328 vec![
1329 (
1330 diagnostic_code::DiagnosticFactTag::RowLayout,
1331 u64::from(row_layout),
1332 ),
1333 (
1334 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1335 u64::from(history_floor),
1336 ),
1337 (
1338 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1339 u64::from(current_layout),
1340 ),
1341 ],
1342 )
1343 }
1344
1345 pub(crate) fn persisted_row_slot_count_mismatch(
1347 row_layout: u32,
1348 expected_slot_count: usize,
1349 actual_slot_count: usize,
1350 ) -> Self {
1351 Self::with_diagnostic_facts(
1352 ErrorClass::Corruption,
1353 ErrorOrigin::Serialize,
1354 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1355 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1356 }),
1357 vec![
1358 (
1359 diagnostic_code::DiagnosticFactTag::RowLayout,
1360 u64::from(row_layout),
1361 ),
1362 (
1363 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1364 expected_slot_count as u64,
1365 ),
1366 (
1367 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1368 actual_slot_count as u64,
1369 ),
1370 ],
1371 )
1372 }
1373
1374 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1376 Self::persisted_row_field_decode_corruption(field_name)
1377 }
1378
1379 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1381 Self::persisted_row_decode_corruption()
1382 }
1383
1384 pub(crate) fn persisted_row_field_kind_decode_failed(
1386 field_name: &str,
1387 _field_kind: impl fmt::Debug,
1388 _detail: impl Sized,
1389 ) -> Self {
1390 Self::persisted_row_field_decode_corruption(field_name)
1391 }
1392
1393 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1395 Self::persisted_row_field_decode_corruption(field_name)
1396 }
1397
1398 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1400 Self::persisted_row_field_decode_corruption(field_name)
1401 }
1402
1403 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1405 Self::persisted_row_field_decode_corruption(field_name)
1406 }
1407
1408 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1410 Self::persisted_row_field_decode_corruption(field_name)
1411 }
1412
1413 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1415 Self::persisted_row_field_decode_corruption(field_name)
1416 }
1417
1418 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1420 Self::index_invariant()
1421 }
1422
1423 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1425 _model_path: &str,
1426 _slot: usize,
1427 ) -> Self {
1428 Self::index_invariant()
1429 }
1430
1431 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1433 _data_key: impl fmt::Debug,
1434 _detail: impl Sized,
1435 ) -> Self {
1436 Self::persisted_row_decode_corruption()
1437 }
1438
1439 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1441 Self::persisted_row_decode_corruption()
1442 }
1443
1444 pub(crate) fn persisted_row_key_mismatch() -> Self {
1446 Self::store_corruption()
1447 }
1448
1449 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1451 Self::persisted_row_field_decode_corruption(field_name)
1452 }
1453
1454 pub(crate) fn reverse_index_ordinal_overflow(
1456 _source_path: &str,
1457 _field_name: &str,
1458 _target_path: &str,
1459 _detail: impl Sized,
1460 ) -> Self {
1461 Self::index_internal()
1462 }
1463
1464 pub(crate) fn reverse_index_entry_corrupted(
1466 _source_path: &str,
1467 _field_name: &str,
1468 _target_path: &str,
1469 _index_key: impl fmt::Debug,
1470 _detail: impl Sized,
1471 ) -> Self {
1472 Self::index_corruption()
1473 }
1474
1475 pub(crate) fn relation_target_store_missing(
1477 _source_path: &str,
1478 _field_name: &str,
1479 _target_path: &str,
1480 _store_path: &str,
1481 _detail: impl Sized,
1482 ) -> Self {
1483 Self::executor_internal()
1484 }
1485
1486 pub(crate) fn relation_target_primary_key_arity_mismatch(
1488 expected_arity: usize,
1489 actual_arity: usize,
1490 ) -> Self {
1491 Self::with_diagnostic_facts(
1492 ErrorClass::Internal,
1493 ErrorOrigin::Executor,
1494 None,
1495 vec![
1496 (
1497 diagnostic_code::DiagnosticFactTag::ComponentKind,
1498 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1499 ),
1500 (
1501 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1502 expected_arity as u64,
1503 ),
1504 (
1505 diagnostic_code::DiagnosticFactTag::ActualArity,
1506 actual_arity as u64,
1507 ),
1508 ],
1509 )
1510 }
1511
1512 pub(crate) fn relation_target_key_decode_failed(
1514 _context_label: &str,
1515 _source_path: &str,
1516 _field_name: &str,
1517 _target_path: &str,
1518 _detail: impl Sized,
1519 ) -> Self {
1520 Self::identity_corruption()
1521 }
1522
1523 pub(crate) fn relation_target_entity_mismatch(
1525 _context_label: &str,
1526 _source_path: &str,
1527 _field_name: &str,
1528 _target_path: &str,
1529 _target_entity_name: &str,
1530 expected_tag: u64,
1531 actual_tag: u64,
1532 ) -> Self {
1533 Self::with_diagnostic_facts(
1534 ErrorClass::Corruption,
1535 ErrorOrigin::Store,
1536 None,
1537 vec![
1538 (
1539 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1540 expected_tag,
1541 ),
1542 (
1543 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1544 actual_tag,
1545 ),
1546 ],
1547 )
1548 }
1549
1550 pub(crate) fn relation_source_row_decode_failed(
1552 _source_path: &str,
1553 _field_name: &str,
1554 _target_path: &str,
1555 _detail: impl Sized,
1556 ) -> Self {
1557 Self::persisted_row_decode_corruption()
1558 }
1559
1560 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1562 _source_path: &str,
1563 _field_name: &str,
1564 _target_path: &str,
1565 ) -> Self {
1566 Self::persisted_row_decode_corruption()
1567 }
1568
1569 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1571 Self::persisted_row_decode_corruption()
1572 }
1573
1574 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1576 Self::index_corruption()
1577 }
1578
1579 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1581 Self::index_corruption()
1582 }
1583
1584 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1586 Self::index_corruption()
1587 }
1588
1589 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1591 Self::index_corruption()
1592 }
1593
1594 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1596 Self::index_corruption()
1597 }
1598
1599 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1601 Self::index_corruption()
1602 }
1603
1604 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1606 Self::index_corruption()
1607 }
1608
1609 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1611 Self::index_corruption()
1612 }
1613
1614 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1616 Self::index_corruption()
1617 }
1618
1619 pub(crate) fn identity_corruption() -> Self {
1621 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1622 }
1623
1624 pub(crate) fn identity_state_corruption() -> Self {
1626 Self::identity_corruption()
1627 }
1628
1629 pub(crate) fn identity_state_conflict() -> Self {
1631 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1632 }
1633
1634 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1636 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1637 }
1638
1639 pub(crate) fn identity_exhausted() -> Self {
1641 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1642 }
1643
1644 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1646 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1647 }
1648
1649 #[cold]
1651 #[inline(never)]
1652 pub(crate) fn store_unsupported() -> Self {
1653 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1654 }
1655
1656 pub(crate) fn schema_application_conflict() -> Self {
1658 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1659 }
1660
1661 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1663 let class = match reason.diagnostic_code() {
1664 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1665 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1666 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1667 _ => ErrorClass::Internal,
1668 };
1669 Self {
1670 class,
1671 origin: ErrorOrigin::Store,
1672 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1673 }
1674 }
1675
1676 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1678 Self {
1679 class: ErrorClass::Unsupported,
1680 origin: ErrorOrigin::Store,
1681 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1682 }
1683 }
1684
1685 #[cfg(feature = "sql")]
1687 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1688 Self {
1689 class: ErrorClass::Unsupported,
1690 origin: ErrorOrigin::Store,
1691 detail: Some(ErrorDetail::Store(
1692 StoreError::SchemaDdlRewriteRequiresMigration,
1693 )),
1694 }
1695 }
1696
1697 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1699 Self {
1700 class: ErrorClass::Unsupported,
1701 origin: ErrorOrigin::Store,
1702 detail: Some(ErrorDetail::Store(
1703 StoreError::JournalMutationRevisionExhausted,
1704 )),
1705 }
1706 }
1707
1708 pub(crate) fn schema_transition_budget_exceeded(
1710 resource: SchemaTransitionBudgetResource,
1711 ) -> Self {
1712 Self {
1713 class: ErrorClass::Unsupported,
1714 origin: ErrorOrigin::Store,
1715 detail: Some(ErrorDetail::Store(
1716 StoreError::SchemaTransitionBudgetExceeded { resource },
1717 )),
1718 }
1719 }
1720
1721 pub(crate) fn unsupported_entity_tag_in_data_store(
1723 _entity_tag: crate::types::EntityTag,
1724 ) -> Self {
1725 Self::store_unsupported()
1726 }
1727
1728 #[cfg(not(test))]
1730 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1731 Self::store_internal()
1732 }
1733
1734 pub(crate) fn index_unsupported() -> Self {
1736 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1737 }
1738
1739 pub(crate) fn index_component_exceeds_max_size_at(
1741 entity_tag: u64,
1742 physical_generation: u64,
1743 component_index: usize,
1744 actual_length: usize,
1745 limit: usize,
1746 ) -> Self {
1747 Self::with_diagnostic_facts(
1748 ErrorClass::Unsupported,
1749 ErrorOrigin::Index,
1750 None,
1751 vec![
1752 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1753 (
1754 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1755 physical_generation,
1756 ),
1757 (
1758 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1759 component_index as u64,
1760 ),
1761 (
1762 diagnostic_code::DiagnosticFactTag::ComponentKind,
1763 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1764 ),
1765 (
1766 diagnostic_code::DiagnosticFactTag::ActualLength,
1767 actual_length as u64,
1768 ),
1769 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1770 ],
1771 )
1772 }
1773
1774 pub(crate) fn index_component_exceeds_max_size() -> Self {
1777 Self::index_unsupported()
1778 }
1779
1780 pub(crate) fn serialize_unsupported() -> Self {
1782 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1783 }
1784
1785 pub(crate) fn cursor_invalid_continuation() -> Self {
1787 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1788 }
1789
1790 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1792 Self::new(
1793 ErrorClass::IncompatiblePersistedFormat,
1794 ErrorOrigin::Serialize,
1795 )
1796 }
1797
1798 #[cfg(feature = "sql")]
1801 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1802 Self {
1803 class: ErrorClass::Unsupported,
1804 origin: ErrorOrigin::Query,
1805 detail: Some(ErrorDetail::Query(
1806 QueryErrorDetail::UnsupportedSqlFeature { feature },
1807 )),
1808 }
1809 }
1810
1811 #[cfg(feature = "sql")]
1814 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1815 Self {
1816 class: ErrorClass::Unsupported,
1817 origin: ErrorOrigin::Query,
1818 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1819 }
1820 }
1821
1822 #[cfg(feature = "sql")]
1824 pub(crate) fn query_sql_lowering_with_facts(
1825 reason: diagnostic_code::SqlLoweringCode,
1826 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1827 ) -> Self {
1828 Self::with_diagnostic_facts(
1829 ErrorClass::Unsupported,
1830 ErrorOrigin::Query,
1831 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1832 facts,
1833 )
1834 }
1835
1836 pub(crate) fn query_unsupported_projection(
1839 reason: diagnostic_code::QueryProjectionCode,
1840 ) -> Self {
1841 Self {
1842 class: ErrorClass::Unsupported,
1843 origin: ErrorOrigin::Query,
1844 detail: Some(ErrorDetail::Query(
1845 QueryErrorDetail::UnsupportedProjection { reason },
1846 )),
1847 }
1848 }
1849
1850 pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1852 Self {
1853 class: ErrorClass::Unsupported,
1854 origin: ErrorOrigin::Query,
1855 detail: Some(ErrorDetail::Query(
1856 QueryErrorDetail::UnknownAggregateTargetField,
1857 )),
1858 }
1859 }
1860
1861 #[cfg(feature = "sql")]
1864 pub(crate) fn query_sql_surface_mismatch(
1865 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1866 ) -> Self {
1867 Self {
1868 class: ErrorClass::Unsupported,
1869 origin: ErrorOrigin::Query,
1870 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1871 mismatch,
1872 })),
1873 }
1874 }
1875
1876 pub(crate) fn query_sql_write_boundary(
1878 boundary: diagnostic_code::SqlWriteBoundaryCode,
1879 ) -> Self {
1880 Self {
1881 class: ErrorClass::Unsupported,
1882 origin: ErrorOrigin::Query,
1883 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1884 boundary,
1885 })),
1886 }
1887 }
1888
1889 pub(crate) fn query_sql_write_boundary_with_facts(
1891 boundary: diagnostic_code::SqlWriteBoundaryCode,
1892 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1893 ) -> Self {
1894 Self::with_diagnostic_facts(
1895 ErrorClass::Unsupported,
1896 ErrorOrigin::Query,
1897 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1898 facts,
1899 )
1900 }
1901
1902 pub fn store_not_found(_key: impl Sized) -> Self {
1903 Self {
1904 class: ErrorClass::NotFound,
1905 origin: ErrorOrigin::Store,
1906 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1907 }
1908 }
1909
1910 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1912 Self::store_unsupported()
1913 }
1914
1915 #[cold]
1917 #[inline(never)]
1918 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1919 Self::new(ErrorClass::Corruption, origin)
1920 }
1921
1922 #[cold]
1924 #[inline(never)]
1925 pub(crate) fn index_plan_index_corruption() -> Self {
1926 Self::index_plan_corruption(ErrorOrigin::Index)
1927 }
1928
1929 #[cold]
1931 #[inline(never)]
1932 pub(crate) fn index_plan_store_corruption() -> Self {
1933 Self::index_plan_corruption(ErrorOrigin::Store)
1934 }
1935
1936 #[cold]
1938 #[inline(never)]
1939 pub(crate) fn index_plan_serialize_corruption() -> Self {
1940 Self::index_plan_corruption(ErrorOrigin::Serialize)
1941 }
1942
1943 #[cfg(test)]
1945 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1946 Self::new(ErrorClass::InvariantViolation, origin)
1947 }
1948
1949 #[cfg(test)]
1951 pub(crate) fn index_plan_store_invariant() -> Self {
1952 Self::index_plan_invariant(ErrorOrigin::Store)
1953 }
1954
1955 pub(crate) fn index_conflict() -> Self {
1961 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1962 }
1963}
1964
1965impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1966 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1967 Self {
1968 class: ErrorClass::Unsupported,
1969 origin: ErrorOrigin::Query,
1970 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1971 reason,
1972 })),
1973 }
1974 }
1975}
1976
1977impl fmt::Debug for InternalError {
1978 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1979 fmt_compact_diagnostic(
1980 f,
1981 self.diagnostic_code(),
1982 self.detail
1983 .as_ref()
1984 .and_then(ErrorDetail::diagnostic_detail),
1985 )
1986 }
1987}
1988
1989impl fmt::Display for InternalError {
1990 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1991 f.write_str(self.message())
1992 }
1993}
1994
1995impl std::error::Error for InternalError {}
1996
1997#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2006pub enum ConstraintValuePathComponent {
2007 RootField { field_id: u32 },
2009
2010 RecordMember {
2012 composite_type_id: u32,
2013 member_id: u32,
2014 },
2015
2016 TupleElement {
2018 composite_type_id: u32,
2019 ordinal: u32,
2020 },
2021
2022 Newtype { composite_type_id: u32 },
2024
2025 EnumVariant { enum_type_id: u32, variant_id: u32 },
2027
2028 ListElement { index: u32 },
2030
2031 SetElement { index: u32 },
2033
2034 MapEntryKey { index: u32 },
2036
2037 MapEntryValue { index: u32 },
2039}
2040
2041impl fmt::Display for ConstraintValuePathComponent {
2042 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2043 match self {
2044 Self::RootField { field_id } => write!(f, "field#{field_id}"),
2045 Self::RecordMember {
2046 composite_type_id,
2047 member_id,
2048 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2049 Self::TupleElement {
2050 composite_type_id,
2051 ordinal,
2052 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2053 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2054 Self::EnumVariant {
2055 enum_type_id,
2056 variant_id,
2057 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2058 Self::ListElement { index } => write!(f, "list[{index}]"),
2059 Self::SetElement { index } => write!(f, "set[{index}]"),
2060 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2061 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2062 }
2063 }
2064}
2065
2066#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2073pub struct ConstraintValuePath {
2074 components: Vec<ConstraintValuePathComponent>,
2075}
2076
2077impl ConstraintValuePath {
2078 #[must_use]
2080 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2081 Self { components }
2082 }
2083
2084 #[must_use]
2086 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2087 self.components.as_slice()
2088 }
2089}
2090
2091impl fmt::Display for ConstraintValuePath {
2092 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2093 for (ordinal, component) in self.components.iter().enumerate() {
2094 if ordinal != 0 {
2095 f.write_str("/")?;
2096 }
2097 component.fmt(f)?;
2098 }
2099 Ok(())
2100 }
2101}
2102
2103#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2112pub struct ConstraintValidationFindingOutput {
2113 accepted_schema_fingerprint: [u8; 16],
2114 entity_tag: u64,
2115 constraint_id: u32,
2116 primary_key: Vec<u8>,
2117 field_ids: Vec<u32>,
2118 value_path: Option<ConstraintValuePath>,
2119 error_code: u16,
2120}
2121
2122impl ConstraintValidationFindingOutput {
2123 #[must_use]
2125 pub(crate) const fn new(
2126 accepted_schema_fingerprint: [u8; 16],
2127 entity_tag: u64,
2128 constraint_id: u32,
2129 primary_key: Vec<u8>,
2130 field_ids: Vec<u32>,
2131 value_path: Option<ConstraintValuePath>,
2132 error_code: u16,
2133 ) -> Self {
2134 Self {
2135 accepted_schema_fingerprint,
2136 entity_tag,
2137 constraint_id,
2138 primary_key,
2139 field_ids,
2140 value_path,
2141 error_code,
2142 }
2143 }
2144
2145 #[must_use]
2147 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2148 self.accepted_schema_fingerprint
2149 }
2150
2151 #[must_use]
2153 pub const fn entity_tag(&self) -> u64 {
2154 self.entity_tag
2155 }
2156
2157 #[must_use]
2159 pub const fn constraint_id(&self) -> u32 {
2160 self.constraint_id
2161 }
2162
2163 #[must_use]
2165 pub const fn primary_key(&self) -> &[u8] {
2166 self.primary_key.as_slice()
2167 }
2168
2169 #[must_use]
2171 pub const fn field_ids(&self) -> &[u32] {
2172 self.field_ids.as_slice()
2173 }
2174
2175 #[must_use]
2177 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2178 self.value_path.as_ref()
2179 }
2180
2181 #[must_use]
2183 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2184 diagnostic_code::ErrorCode::from_raw(self.error_code)
2185 }
2186
2187 #[must_use]
2189 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2190 self.error_code().class()
2191 }
2192}
2193
2194#[derive(Clone)]
2196pub(crate) struct AcceptedConstraintFactContext {
2197 fingerprint_method: u8,
2198 accepted_schema_fingerprint: [u8; 16],
2199 entity_tag: u64,
2200 constraint_id: u32,
2201 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2202 mutation: Option<MutationDiagnosticContext>,
2203 value_path: Option<ConstraintValuePath>,
2204}
2205
2206impl AcceptedConstraintFactContext {
2207 #[must_use]
2208 pub(crate) fn write_admission(
2209 fingerprint_method: u8,
2210 accepted_schema_fingerprint: [u8; 16],
2211 entity_tag: u64,
2212 constraint_id: u32,
2213 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2214 mutation: Option<MutationDiagnosticContext>,
2215 value_path: Option<ConstraintValuePath>,
2216 ) -> Self {
2217 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2218 Self {
2219 fingerprint_method,
2220 accepted_schema_fingerprint,
2221 entity_tag,
2222 constraint_id,
2223 constraint_kind,
2224 mutation,
2225 value_path,
2226 }
2227 }
2228
2229 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2230 let high = u64::from_be_bytes([
2231 self.accepted_schema_fingerprint[0],
2232 self.accepted_schema_fingerprint[1],
2233 self.accepted_schema_fingerprint[2],
2234 self.accepted_schema_fingerprint[3],
2235 self.accepted_schema_fingerprint[4],
2236 self.accepted_schema_fingerprint[5],
2237 self.accepted_schema_fingerprint[6],
2238 self.accepted_schema_fingerprint[7],
2239 ]);
2240 let low = u64::from_be_bytes([
2241 self.accepted_schema_fingerprint[8],
2242 self.accepted_schema_fingerprint[9],
2243 self.accepted_schema_fingerprint[10],
2244 self.accepted_schema_fingerprint[11],
2245 self.accepted_schema_fingerprint[12],
2246 self.accepted_schema_fingerprint[13],
2247 self.accepted_schema_fingerprint[14],
2248 self.accepted_schema_fingerprint[15],
2249 ]);
2250 let path_len = self
2251 .value_path
2252 .as_ref()
2253 .map_or(0, |path| path.components().len());
2254 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2255 1 + usize::from(mutation.batch_position.is_some())
2256 });
2257 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2258 facts.push((
2259 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2260 u64::from(self.fingerprint_method),
2261 ));
2262 facts.push((
2263 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2264 high,
2265 ));
2266 facts.push((
2267 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2268 low,
2269 ));
2270 facts.push((
2271 diagnostic_code::DiagnosticFactTag::EntityTag,
2272 self.entity_tag,
2273 ));
2274 facts.push((
2275 diagnostic_code::DiagnosticFactTag::ConstraintId,
2276 u64::from(self.constraint_id),
2277 ));
2278 facts.push((
2279 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2280 self.constraint_kind.raw(),
2281 ));
2282 facts.push((
2283 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2284 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2285 ));
2286 if let Some(mutation) = self.mutation {
2287 mutation.append_operation_facts(&mut facts);
2288 }
2289 if let Some(path) = self.value_path {
2290 for component in path.components {
2291 facts.push(constraint_value_path_fact(component));
2292 }
2293 }
2294 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2295 facts
2296 }
2297}
2298
2299fn constraint_value_path_fact(
2300 component: ConstraintValuePathComponent,
2301) -> (diagnostic_code::DiagnosticFactTag, u64) {
2302 use diagnostic_code::DiagnosticFactTag;
2303 match component {
2304 ConstraintValuePathComponent::RootField { field_id } => {
2305 (DiagnosticFactTag::RootField, u64::from(field_id))
2306 }
2307 ConstraintValuePathComponent::RecordMember {
2308 composite_type_id,
2309 member_id,
2310 } => (
2311 DiagnosticFactTag::RecordMember,
2312 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2313 ),
2314 ConstraintValuePathComponent::TupleElement {
2315 composite_type_id,
2316 ordinal,
2317 } => (
2318 DiagnosticFactTag::TupleElement,
2319 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2320 ),
2321 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2322 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2323 }
2324 ConstraintValuePathComponent::EnumVariant {
2325 enum_type_id,
2326 variant_id,
2327 } => (
2328 DiagnosticFactTag::EnumVariant,
2329 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2330 ),
2331 ConstraintValuePathComponent::ListElement { index } => {
2332 (DiagnosticFactTag::ListElement, u64::from(index))
2333 }
2334 ConstraintValuePathComponent::SetElement { index } => {
2335 (DiagnosticFactTag::SetElement, u64::from(index))
2336 }
2337 ConstraintValuePathComponent::MapEntryKey { index } => {
2338 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2339 }
2340 ConstraintValuePathComponent::MapEntryValue { index } => {
2341 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2342 }
2343 }
2344}
2345
2346pub enum ErrorDetail {
2354 DiagnosticFacts(Box<DiagnosticFactDetail>),
2356 Executor(ExecutorErrorDetail),
2358 Store(StoreError),
2359 Query(QueryErrorDetail),
2360 Recovery(RecoveryErrorDetail),
2361 }
2364
2365pub enum ExecutorErrorDetail {
2367 MutationRequiredFieldMissing,
2369 MutationManagedTimestampRegression,
2371 MutationDatabaseOwnedFieldExplicit,
2373 MutationBatchEmpty,
2375 MutationBatchTooManyItems,
2377 MutationBatchStagedBytesExceeded,
2379 MutationBatchResultBytesExceeded,
2381 MutationBatchEntityMismatch,
2383 MutationBatchDuplicateKey,
2385 AcceptedRowConstraintProgramCorrupt,
2387}
2388
2389pub enum RecoveryErrorDetail {
2396 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2397
2398 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2399}
2400
2401#[derive(Clone, Copy, Eq, PartialEq)]
2403pub enum RecoveryFormatMarkerError {
2404 Magic,
2405 Checksum,
2406 State,
2407}
2408
2409impl RecoveryFormatMarkerError {
2410 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2411 match self {
2412 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2413 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2414 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2415 }
2416 }
2417}
2418
2419pub enum StoreError {
2427 NotFound,
2428
2429 Corrupt,
2430
2431 InvariantViolation,
2432
2433 SchemaDdlPublicationRaceLost,
2434
2435 SchemaDdlRewriteRequiresMigration,
2436
2437 SchemaMigration {
2438 reason: diagnostic_code::SchemaMigrationCode,
2439 },
2440
2441 SchemaRowLayoutVersionExhausted,
2442
2443 JournalMutationRevisionExhausted,
2444
2445 SchemaTransitionBudgetExceeded {
2446 resource: SchemaTransitionBudgetResource,
2447 },
2448
2449 SchemaGeneratedFieldAfterDdlField,
2451
2452 SchemaGeneratedConstraintActivationStale,
2454}
2455
2456pub enum QueryErrorDetail {
2463 NumericOverflow,
2464
2465 NumericNotRepresentable,
2466
2467 UnsupportedSqlFeature {
2468 feature: diagnostic_code::SqlFeatureCode,
2469 },
2470
2471 SqlLowering {
2472 reason: diagnostic_code::SqlLoweringCode,
2473 },
2474
2475 UnsupportedProjection {
2476 reason: diagnostic_code::QueryProjectionCode,
2477 },
2478
2479 UnknownAggregateTargetField,
2480
2481 ResultShapeMismatch {
2482 reason: diagnostic_code::QueryResultShapeCode,
2483 },
2484
2485 QueryReadAdmission {
2486 reason: diagnostic_code::QueryReadAdmissionCode,
2487 },
2488
2489 SqlSurfaceMismatch {
2490 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2491 },
2492
2493 SqlWriteBoundary {
2494 boundary: diagnostic_code::SqlWriteBoundaryCode,
2495 },
2496
2497 SchemaDdlAdmission {
2498 error: SchemaDdlAdmissionError,
2499 },
2500
2501 StaleSchemaRevision,
2502}
2503
2504impl fmt::Display for QueryErrorDetail {
2505 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2506 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2507 }
2508}
2509
2510impl std::error::Error for QueryErrorDetail {}
2511
2512#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2520pub enum SchemaTransitionBudgetResource {
2521 DeletionKeys,
2523 ProjectionEntries,
2525 ProjectionWorkUnits,
2527 SourceRows,
2529 SourceRowBytes,
2531 StagedRawBytes,
2533}
2534
2535#[derive(Clone, Copy, Eq, PartialEq)]
2544pub enum SchemaDdlAdmissionError {
2545 MissingExpectedSchemaVersion,
2546
2547 MissingNextSchemaVersion,
2548
2549 StaleExpectedSchemaVersion,
2550
2551 InvalidExpectedSchemaVersion,
2552
2553 InvalidNextSchemaVersion,
2554
2555 AcceptedSchemaChangeWithoutVersionBump,
2556
2557 EmptyVersionBump,
2558
2559 VersionGap,
2560
2561 VersionRollback,
2562
2563 FingerprintMethodMismatch,
2564
2565 UnsupportedTransitionClass,
2566
2567 PhysicalRunnerMissing,
2568
2569 ValidationFailed,
2570
2571 PublicationRaceLost,
2572
2573 InvalidAddColumnDefault,
2574
2575 InvalidAlterColumnDefault,
2576
2577 RowLayoutVersionExhausted,
2578
2579 GeneratedIndexDropRejected,
2580
2581 SchemaRewriteRequiresMigration,
2582
2583 SchemaTransitionBudgetExceeded {
2584 resource: SchemaTransitionBudgetResource,
2585 },
2586
2587 GeneratedFieldDefaultChangeRejected,
2588
2589 GeneratedFieldNullabilityChangeRejected,
2590}
2591
2592impl fmt::Display for SchemaDdlAdmissionError {
2593 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2594 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2595 }
2596}
2597
2598impl std::error::Error for SchemaDdlAdmissionError {}
2599
2600impl fmt::Debug for ErrorDetail {
2601 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2602 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2603 }
2604}
2605
2606impl fmt::Debug for ExecutorErrorDetail {
2607 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2608 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2609 }
2610}
2611
2612impl fmt::Debug for StoreError {
2613 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2614 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2615 }
2616}
2617
2618impl fmt::Debug for QueryErrorDetail {
2619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2620 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2621 }
2622}
2623
2624impl fmt::Debug for RecoveryErrorDetail {
2625 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2626 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2627 }
2628}
2629
2630impl fmt::Debug for RecoveryFormatMarkerError {
2631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2632 fmt_compact_diagnostic(
2633 f,
2634 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2635 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2636 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2637 }),
2638 )
2639 }
2640}
2641
2642impl fmt::Debug for SchemaDdlAdmissionError {
2643 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2644 fmt_compact_diagnostic(
2645 f,
2646 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2647 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2648 reason: self.diagnostic_code(),
2649 }),
2650 )
2651 }
2652}
2653
2654fn fmt_compact_diagnostic(
2655 f: &mut fmt::Formatter<'_>,
2656 code: diagnostic_code::DiagnosticCode,
2657 detail: Option<diagnostic_code::DiagnosticDetail>,
2658) -> fmt::Result {
2659 write!(
2660 f,
2661 "{}",
2662 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2663 )
2664}
2665
2666impl ErrorDetail {
2667 #[must_use]
2669 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2670 match self {
2671 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2672 Self::Executor(error) => error.diagnostic_code(),
2673 Self::Store(error) => error.diagnostic_code(),
2674 Self::Query(error) => error.diagnostic_code(),
2675 Self::Recovery(error) => error.diagnostic_code(),
2676 }
2677 }
2678
2679 #[must_use]
2681 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2682 match self {
2683 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2684 Self::Executor(error) => error.diagnostic_detail(),
2685 Self::Store(error) => error.diagnostic_detail(),
2686 Self::Query(error) => error.diagnostic_detail(),
2687 Self::Recovery(error) => error.diagnostic_detail(),
2688 }
2689 }
2690
2691 #[must_use]
2693 #[cold]
2694 #[inline(never)]
2695 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2696 match self {
2697 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2698 Self::Executor(error) => error.diagnostic_facts(),
2699 Self::Query(error) => error.diagnostic_facts(),
2700 Self::Recovery(error) => error.diagnostic_facts(),
2701 Self::Store(_) => Vec::new(),
2702 }
2703 }
2704}
2705
2706impl ExecutorErrorDetail {
2707 #[must_use]
2709 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2710 match self {
2711 Self::MutationRequiredFieldMissing
2712 | Self::MutationDatabaseOwnedFieldExplicit
2713 | Self::MutationBatchEmpty
2714 | Self::MutationBatchTooManyItems
2715 | Self::MutationBatchStagedBytesExceeded
2716 | Self::MutationBatchResultBytesExceeded => {
2717 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2718 }
2719 Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2720 diagnostic_code::DiagnosticCode::RuntimeConflict
2721 }
2722 Self::MutationManagedTimestampRegression => {
2723 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2724 }
2725 Self::AcceptedRowConstraintProgramCorrupt => {
2726 diagnostic_code::DiagnosticCode::RuntimeCorruption
2727 }
2728 }
2729 }
2730
2731 #[must_use]
2733 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2734 match self {
2735 Self::MutationRequiredFieldMissing => {
2736 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2737 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2738 })
2739 }
2740 Self::MutationDatabaseOwnedFieldExplicit => {
2741 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2742 boundary:
2743 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2744 })
2745 }
2746 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2747 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2748 }),
2749 Self::MutationBatchTooManyItems => {
2750 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2751 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2752 })
2753 }
2754 Self::MutationBatchStagedBytesExceeded => {
2755 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2756 boundary:
2757 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2758 })
2759 }
2760 Self::MutationBatchResultBytesExceeded => {
2761 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2762 boundary:
2763 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2764 })
2765 }
2766 Self::MutationBatchEntityMismatch => {
2767 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2768 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2769 })
2770 }
2771 Self::MutationBatchDuplicateKey => {
2772 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2773 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2774 })
2775 }
2776 Self::MutationManagedTimestampRegression => {
2777 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2778 boundary:
2779 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2780 })
2781 }
2782 Self::AcceptedRowConstraintProgramCorrupt => {
2783 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2784 boundary:
2785 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2786 })
2787 }
2788 }
2789 }
2790
2791 #[must_use]
2793 #[cold]
2794 #[inline(never)]
2795 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2796 Vec::new()
2797 }
2798}
2799
2800impl RecoveryErrorDetail {
2801 #[must_use]
2803 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2804 match self {
2805 Self::UnsupportedFormatVersion { .. } => {
2806 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2807 }
2808 Self::MalformedFormatMarker { .. } => {
2809 diagnostic_code::DiagnosticCode::RuntimeCorruption
2810 }
2811 }
2812 }
2813
2814 #[must_use]
2816 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2817 let kind = match self {
2818 Self::UnsupportedFormatVersion { .. } => {
2819 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2820 }
2821 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2822 };
2823
2824 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2825 }
2826
2827 #[must_use]
2829 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2830 match self {
2831 Self::UnsupportedFormatVersion { found, required } => {
2832 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2833 facts.push((
2834 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2835 u64::from(*required),
2836 ));
2837 if let Some(found) = found {
2838 facts.push((
2839 diagnostic_code::DiagnosticFactTag::ActualVersion,
2840 u64::from(*found),
2841 ));
2842 }
2843 facts
2844 }
2845 Self::MalformedFormatMarker { reason } => vec![(
2846 diagnostic_code::DiagnosticFactTag::DecodeReason,
2847 reason.diagnostic_decode_reason().raw(),
2848 )],
2849 }
2850 }
2851}
2852
2853impl StoreError {
2854 #[must_use]
2856 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2857 match self {
2858 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2859 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2860 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2861 Self::SchemaDdlPublicationRaceLost
2862 | Self::SchemaDdlRewriteRequiresMigration
2863 | Self::SchemaRowLayoutVersionExhausted
2864 | Self::SchemaTransitionBudgetExceeded { .. } => {
2865 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2866 }
2867 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2868 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2869 }
2870 Self::SchemaGeneratedConstraintActivationStale => {
2871 diagnostic_code::DiagnosticCode::RuntimeConflict
2872 }
2873 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2874 }
2875 }
2876
2877 #[must_use]
2879 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2880 match self {
2881 Self::SchemaDdlPublicationRaceLost => {
2882 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2883 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2884 })
2885 }
2886 Self::SchemaDdlRewriteRequiresMigration => {
2887 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2888 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2889 })
2890 }
2891 Self::SchemaMigration { reason } => {
2892 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2893 }
2894 Self::SchemaRowLayoutVersionExhausted => {
2895 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2896 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2897 })
2898 }
2899 Self::JournalMutationRevisionExhausted => {
2900 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2901 boundary:
2902 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2903 })
2904 }
2905 Self::SchemaTransitionBudgetExceeded { .. } => {
2906 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2907 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2908 })
2909 }
2910 Self::SchemaGeneratedFieldAfterDdlField => {
2911 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2912 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2913 })
2914 }
2915 Self::SchemaGeneratedConstraintActivationStale => {
2916 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2917 boundary:
2918 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2919 })
2920 }
2921 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2922 }
2923 }
2924}
2925
2926impl QueryErrorDetail {
2927 #[must_use]
2929 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2930 match self {
2931 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2932 Self::NumericNotRepresentable => {
2933 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2934 }
2935 Self::UnsupportedSqlFeature { .. } => {
2936 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2937 }
2938 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2939 Self::UnsupportedProjection { .. } => {
2940 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2941 }
2942 Self::UnknownAggregateTargetField => {
2943 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2944 }
2945 Self::ResultShapeMismatch { .. } => {
2946 diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2947 }
2948 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2949 Self::SqlSurfaceMismatch { .. } => {
2950 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2951 }
2952 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2953 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2954 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2955 }
2956 }
2957
2958 #[must_use]
2960 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2961 match self {
2962 Self::UnsupportedSqlFeature { feature } => {
2963 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2964 }
2965 Self::SqlLowering { reason } => {
2966 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2967 }
2968 Self::UnsupportedProjection { reason } => {
2969 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2970 }
2971 Self::ResultShapeMismatch { reason } => {
2972 Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2973 }
2974 Self::QueryReadAdmission { reason } => {
2975 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2976 }
2977 Self::SqlSurfaceMismatch { mismatch } => {
2978 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2979 mismatch: *mismatch,
2980 })
2981 }
2982 Self::SqlWriteBoundary { boundary } => {
2983 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2984 boundary: *boundary,
2985 })
2986 }
2987 Self::SchemaDdlAdmission { error } => {
2988 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2989 reason: error.diagnostic_code(),
2990 })
2991 }
2992 Self::NumericOverflow
2993 | Self::NumericNotRepresentable
2994 | Self::UnknownAggregateTargetField
2995 | Self::StaleSchemaRevision => None,
2996 }
2997 }
2998
2999 #[must_use]
3001 #[cold]
3002 #[inline(never)]
3003 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3004 Vec::new()
3005 }
3006}
3007
3008impl SchemaDdlAdmissionError {
3009 #[must_use]
3011 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3012 match self {
3013 Self::MissingExpectedSchemaVersion => {
3014 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3015 }
3016 Self::MissingNextSchemaVersion => {
3017 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3018 }
3019 Self::StaleExpectedSchemaVersion => {
3020 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3021 }
3022 Self::InvalidExpectedSchemaVersion => {
3023 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3024 }
3025 Self::InvalidNextSchemaVersion => {
3026 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3027 }
3028 Self::AcceptedSchemaChangeWithoutVersionBump => {
3029 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3030 }
3031 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3032 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3033 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3034 Self::FingerprintMethodMismatch => {
3035 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3036 }
3037 Self::UnsupportedTransitionClass => {
3038 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3039 }
3040 Self::PhysicalRunnerMissing => {
3041 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3042 }
3043 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3044 Self::PublicationRaceLost => {
3045 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3046 }
3047 Self::InvalidAddColumnDefault => {
3048 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3049 }
3050 Self::InvalidAlterColumnDefault => {
3051 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3052 }
3053 Self::GeneratedIndexDropRejected => {
3054 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3055 }
3056 Self::SchemaRewriteRequiresMigration => {
3057 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3058 }
3059 Self::SchemaTransitionBudgetExceeded { .. } => {
3060 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3061 }
3062 Self::GeneratedFieldDefaultChangeRejected => {
3063 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3064 }
3065 Self::GeneratedFieldNullabilityChangeRejected => {
3066 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3067 }
3068 Self::RowLayoutVersionExhausted => {
3069 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3070 }
3071 }
3072 }
3073}
3074
3075#[repr(u8)]
3082#[derive(Clone, Copy, Eq, PartialEq)]
3083pub enum ErrorClass {
3084 Corruption,
3085 IncompatiblePersistedFormat,
3086 NotFound,
3087 Internal,
3088 Conflict,
3089 Unsupported,
3090 InvariantViolation,
3091}
3092
3093impl ErrorClass {
3094 #[must_use]
3096 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3097 match self {
3098 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3099 diagnostic_code::DiagnosticCode::StoreCorruption
3100 }
3101 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3102 Self::IncompatiblePersistedFormat => {
3103 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3104 }
3105 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3106 diagnostic_code::DiagnosticCode::StoreNotFound
3107 }
3108 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3109 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3110 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3111 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3112 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3113 }
3114 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3115 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3116 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3117 }
3118 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3119 }
3120 }
3121}
3122
3123impl fmt::Debug for ErrorClass {
3124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3125 write!(f, "{}", *self as u8)
3126 }
3127}
3128
3129#[repr(u8)]
3136#[derive(Clone, Copy, Eq, PartialEq)]
3137pub enum ErrorOrigin {
3138 Serialize,
3139 Store,
3140 Index,
3141 Identity,
3142 Query,
3143 Planner,
3144 Cursor,
3145 Recovery,
3146 Response,
3147 Executor,
3148 Interface,
3149}
3150
3151impl ErrorOrigin {
3152 #[must_use]
3154 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3155 match self {
3156 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3157 Self::Store => diagnostic_code::ErrorOrigin::Store,
3158 Self::Index => diagnostic_code::ErrorOrigin::Index,
3159 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3160 Self::Query => diagnostic_code::ErrorOrigin::Query,
3161 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3162 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3163 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3164 Self::Response => diagnostic_code::ErrorOrigin::Response,
3165 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3166 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3167 }
3168 }
3169}
3170
3171impl fmt::Debug for ErrorOrigin {
3172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3173 write!(f, "{}", *self as u8)
3174 }
3175}