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 #[cold]
397 #[inline(never)]
398 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
399 match self.detail {
400 Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
401 self.class,
402 origin,
403 detail.diagnostic.detail().copied(),
404 detail.facts,
405 ),
406 _ => Self::classified(self.class, origin),
407 }
408 }
409
410 #[cold]
412 #[inline(never)]
413 pub(crate) fn index_invariant() -> Self {
414 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
415 }
416
417 pub(crate) fn index_key_field_count_exceeds_max(
419 entity_tag: u64,
420 physical_generation: u64,
421 field_count: usize,
422 max_fields: usize,
423 ) -> Self {
424 Self::with_diagnostic_facts(
425 ErrorClass::InvariantViolation,
426 ErrorOrigin::Index,
427 None,
428 vec![
429 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
430 (
431 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
432 physical_generation,
433 ),
434 (
435 diagnostic_code::DiagnosticFactTag::ComponentKind,
436 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
437 ),
438 (
439 diagnostic_code::DiagnosticFactTag::ActualArity,
440 field_count as u64,
441 ),
442 (
443 diagnostic_code::DiagnosticFactTag::Maximum,
444 max_fields as u64,
445 ),
446 ],
447 )
448 }
449
450 pub(crate) fn index_expression_source_type_mismatch(
452 _index_name: &str,
453 _expression: impl Sized,
454 _expected: impl Sized,
455 _source_label: &str,
456 ) -> Self {
457 Self::index_invariant()
458 }
459
460 #[cold]
463 #[inline(never)]
464 pub(crate) fn planner_executor_invariant() -> Self {
465 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
466 }
467
468 #[cold]
471 #[inline(never)]
472 pub(crate) fn query_executor_invariant() -> Self {
473 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
474 }
475
476 #[cold]
479 #[inline(never)]
480 pub(crate) fn cursor_executor_invariant() -> Self {
481 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
482 }
483
484 #[cold]
486 #[inline(never)]
487 pub(crate) fn executor_invariant() -> Self {
488 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
489 }
490
491 #[cold]
493 #[inline(never)]
494 pub(crate) fn executor_internal() -> Self {
495 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
496 }
497
498 #[cold]
500 #[inline(never)]
501 pub(crate) fn executor_unsupported() -> Self {
502 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
503 }
504
505 #[cold]
507 #[inline(never)]
508 pub(crate) fn mutation_database_owned_field_explicit(
509 context: MutationDiagnosticContext,
510 field_id: u32,
511 ) -> Self {
512 Self::mutation_boundary_with_facts(
513 ErrorClass::Unsupported,
514 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
515 context.facts(Some(field_id)),
516 )
517 }
518
519 #[must_use]
521 #[cold]
522 #[inline(never)]
523 pub(crate) fn mutation_required_field_missing(
524 context: MutationDiagnosticContext,
525 field_id: u32,
526 ) -> Self {
527 Self::mutation_boundary_with_facts(
528 ErrorClass::Unsupported,
529 diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
530 context.facts(Some(field_id)),
531 )
532 }
533
534 #[must_use]
536 #[cold]
537 #[inline(never)]
538 pub(crate) fn mutation_managed_timestamp_regression(
539 context: MutationDiagnosticContext,
540 ) -> Self {
541 Self::mutation_boundary_with_facts(
542 ErrorClass::InvariantViolation,
543 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
544 context.facts(None),
545 )
546 }
547
548 pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
550 Self::mutation_boundary_with_facts(
551 ErrorClass::InvariantViolation,
552 diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
553 context.facts(),
554 )
555 }
556
557 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
559 Self {
560 class: ErrorClass::Corruption,
561 origin: ErrorOrigin::Executor,
562 detail: Some(ErrorDetail::Executor(
563 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
564 )),
565 }
566 }
567
568 pub(crate) fn mutation_constraint_activation_write_blocked(
570 context: AcceptedConstraintFactContext,
571 ) -> Self {
572 Self::mutation_boundary_with_facts(
573 ErrorClass::Conflict,
574 diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
575 context.facts(),
576 )
577 }
578
579 pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
581 Self::executor_invariant()
582 }
583
584 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
586 Self::query_executor_invariant()
587 }
588
589 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
591 Self::query_executor_invariant()
592 }
593
594 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
596 Self::query_executor_invariant()
597 }
598
599 pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
601 Self::query_executor_invariant()
602 }
603
604 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
606 Self::query_executor_invariant()
607 }
608
609 pub(crate) fn index_range_limit_spec_required() -> Self {
611 Self::query_executor_invariant()
612 }
613
614 #[cold]
616 #[inline(never)]
617 pub(crate) fn mutation_atomic_save_duplicate_key(
618 entity_tag: u64,
619 first_position: u32,
620 duplicate_position: u32,
621 ) -> Self {
622 Self::mutation_boundary_with_facts(
623 ErrorClass::Conflict,
624 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
625 vec![
626 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
627 (
628 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
629 u64::from(first_position),
630 ),
631 (
632 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
633 u64::from(duplicate_position),
634 ),
635 ],
636 )
637 }
638
639 #[cold]
641 #[inline(never)]
642 pub(crate) fn mutation_batch_empty() -> Self {
643 Self::mutation_boundary_with_facts(
644 ErrorClass::Unsupported,
645 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
646 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
647 )
648 }
649
650 #[cold]
652 #[inline(never)]
653 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
654 Self::mutation_boundary_with_facts(
655 ErrorClass::Unsupported,
656 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
657 vec![
658 (
659 diagnostic_code::DiagnosticFactTag::ActualCount,
660 actual_count as u64,
661 ),
662 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
663 ],
664 )
665 }
666
667 #[cold]
669 #[inline(never)]
670 pub(crate) fn mutation_batch_staged_bytes_exceeded(
671 actual_bytes: Option<usize>,
672 limit: usize,
673 ) -> Self {
674 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
675 if let Some(actual_bytes) = actual_bytes {
676 facts.push((
677 diagnostic_code::DiagnosticFactTag::ActualLength,
678 actual_bytes as u64,
679 ));
680 }
681 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
682 Self::mutation_boundary_with_facts(
683 ErrorClass::Unsupported,
684 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
685 facts,
686 )
687 }
688
689 #[cold]
691 #[inline(never)]
692 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
693 Self::mutation_boundary_with_facts(
694 ErrorClass::Unsupported,
695 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
696 vec![
697 (
698 diagnostic_code::DiagnosticFactTag::ActualLength,
699 actual_bytes as u64,
700 ),
701 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
702 ],
703 )
704 }
705
706 #[cold]
708 #[inline(never)]
709 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
710 Self::exact_key_batch_boundary_with_facts(
711 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
712 vec![
713 (
714 diagnostic_code::DiagnosticFactTag::ActualCount,
715 actual_count as u64,
716 ),
717 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
718 ],
719 )
720 }
721
722 #[cold]
724 #[inline(never)]
725 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
726 Self::exact_key_batch_bytes_exceeded(
727 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
728 actual_bytes,
729 limit,
730 )
731 }
732
733 #[cold]
735 #[inline(never)]
736 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
737 Self::exact_key_batch_bytes_exceeded(
738 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
739 actual_bytes,
740 limit,
741 )
742 }
743
744 #[cold]
746 #[inline(never)]
747 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
748 Self::exact_key_batch_bytes_exceeded(
749 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
750 actual_bytes,
751 limit,
752 )
753 }
754
755 #[cold]
756 #[inline(never)]
757 fn exact_key_batch_bytes_exceeded(
758 boundary: diagnostic_code::RuntimeBoundaryCode,
759 actual_bytes: usize,
760 limit: usize,
761 ) -> Self {
762 Self::exact_key_batch_boundary_with_facts(
763 boundary,
764 vec![
765 (
766 diagnostic_code::DiagnosticFactTag::ActualLength,
767 actual_bytes as u64,
768 ),
769 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
770 ],
771 )
772 }
773
774 #[cold]
776 #[inline(never)]
777 pub(crate) fn mutation_batch_entity_mismatch(
778 batch_position: u32,
779 expected_entity_tag: u64,
780 actual_entity_tag: u64,
781 ) -> Self {
782 Self::mutation_boundary_with_facts(
783 ErrorClass::Conflict,
784 diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
785 vec![
786 (
787 diagnostic_code::DiagnosticFactTag::BatchPosition,
788 u64::from(batch_position),
789 ),
790 (
791 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
792 expected_entity_tag,
793 ),
794 (
795 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
796 actual_entity_tag,
797 ),
798 ],
799 )
800 }
801
802 pub(crate) fn mutation_index_store_generation_changed(
804 _expected_generation: u64,
805 _observed_generation: u64,
806 ) -> Self {
807 Self::executor_invariant()
808 }
809
810 #[cold]
812 #[inline(never)]
813 pub(crate) fn planner_invariant() -> Self {
814 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
815 }
816
817 pub(crate) fn query_invalid_logical_plan() -> Self {
819 Self::planner_invariant()
820 }
821
822 pub(crate) fn store_invariant() -> Self {
824 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
825 }
826
827 #[cold]
829 #[inline(never)]
830 pub(crate) fn store_internal() -> Self {
831 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
832 }
833
834 pub(crate) fn commit_memory_id_unconfigured() -> Self {
836 Self::store_internal()
837 }
838
839 pub(crate) fn commit_store_uninitialized() -> Self {
841 Self::store_invariant()
842 }
843
844 pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
846 Self::with_diagnostic_facts(
847 ErrorClass::Internal,
848 ErrorOrigin::Store,
849 None,
850 vec![
851 (
852 diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
853 u64::from(cached_id),
854 ),
855 (
856 diagnostic_code::DiagnosticFactTag::ActualMemoryId,
857 u64::from(configured_id),
858 ),
859 ],
860 )
861 }
862
863 pub(crate) fn commit_memory_stable_key_mismatch(
865 _cached_key: &str,
866 _configured_key: &str,
867 ) -> Self {
868 Self::store_internal()
869 }
870
871 pub(crate) fn database_incarnation_generation_failed() -> Self {
873 Self::store_internal()
874 }
875
876 pub(crate) fn database_incarnation_invalid() -> Self {
878 Self::store_corruption()
879 }
880
881 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
883 Self {
884 class: ErrorClass::IncompatiblePersistedFormat,
885 origin: ErrorOrigin::Recovery,
886 detail: Some(ErrorDetail::Recovery(
887 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
888 )),
889 }
890 }
891
892 pub(crate) fn recovery_malformed_database_format_marker(
894 reason: RecoveryFormatMarkerError,
895 ) -> Self {
896 Self {
897 class: ErrorClass::Corruption,
898 origin: ErrorOrigin::Recovery,
899 detail: Some(ErrorDetail::Recovery(
900 RecoveryErrorDetail::MalformedFormatMarker { reason },
901 )),
902 }
903 }
904
905 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
907 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
908 }
909
910 pub(crate) fn commit_control_memory_growth_failed() -> Self {
912 Self::store_internal()
913 }
914
915 #[cfg(not(test))]
917 pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
918 Self::store_internal()
919 }
920
921 pub(crate) fn recovery_effect_verification_failed() -> Self {
923 Self::store_corruption()
924 }
925
926 #[cold]
928 #[inline(never)]
929 pub(crate) fn index_internal() -> Self {
930 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
931 }
932
933 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
935 Self::index_internal()
936 }
937
938 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
940 Self::index_internal()
941 }
942
943 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
945 Self::index_internal()
946 }
947
948 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
950 Self::index_internal()
951 }
952
953 #[cfg(test)]
955 pub(crate) fn query_internal() -> Self {
956 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
957 }
958
959 #[cold]
961 #[inline(never)]
962 pub(crate) fn query_unsupported() -> Self {
963 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
964 }
965
966 #[cold]
969 #[inline(never)]
970 pub(crate) fn query_stale_accepted_schema_revision(
971 expected_revision: u64,
972 current_revision: Option<u64>,
973 ) -> Self {
974 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
975 facts.push((
976 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
977 expected_revision,
978 ));
979 if let Some(current_revision) = current_revision {
980 facts.push((
981 diagnostic_code::DiagnosticFactTag::CurrentRevision,
982 current_revision,
983 ));
984 }
985 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
986 }
987
988 #[cold]
990 #[inline(never)]
991 #[cfg(feature = "sql")]
992 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
993 Self {
994 class: ErrorClass::Unsupported,
995 origin: ErrorOrigin::Query,
996 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
997 error,
998 })),
999 }
1000 }
1001
1002 #[cold]
1004 #[inline(never)]
1005 pub(crate) fn query_numeric_overflow() -> Self {
1006 Self {
1007 class: ErrorClass::Unsupported,
1008 origin: ErrorOrigin::Query,
1009 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1010 }
1011 }
1012
1013 #[cold]
1016 #[inline(never)]
1017 pub(crate) fn query_numeric_not_representable() -> Self {
1018 Self {
1019 class: ErrorClass::Unsupported,
1020 origin: ErrorOrigin::Query,
1021 detail: Some(ErrorDetail::Query(
1022 QueryErrorDetail::NumericNotRepresentable,
1023 )),
1024 }
1025 }
1026
1027 #[cold]
1029 #[inline(never)]
1030 pub(crate) fn serialize_internal() -> Self {
1031 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1032 }
1033
1034 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1036 Self::persisted_row_encode_internal()
1037 }
1038
1039 pub(crate) fn persisted_row_encode_internal() -> Self {
1041 Self::serialize_internal()
1042 }
1043
1044 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1046 Self::persisted_row_encode_internal()
1047 }
1048
1049 #[cold]
1051 #[inline(never)]
1052 pub(crate) fn store_corruption() -> Self {
1053 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1054 }
1055
1056 pub(crate) fn commit_corruption() -> Self {
1058 Self::store_corruption()
1059 }
1060
1061 pub(crate) fn commit_component_corruption() -> Self {
1063 Self::commit_corruption()
1064 }
1065
1066 pub(crate) fn commit_id_generation_failed() -> Self {
1068 Self::store_internal()
1069 }
1070
1071 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1073 Self::store_unsupported()
1074 }
1075
1076 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1078 Self::with_diagnostic_facts(
1079 ErrorClass::Corruption,
1080 ErrorOrigin::Store,
1081 None,
1082 vec![
1083 (
1084 diagnostic_code::DiagnosticFactTag::ComponentKind,
1085 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1086 ),
1087 (
1088 diagnostic_code::DiagnosticFactTag::ActualLength,
1089 actual_length as u64,
1090 ),
1091 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1092 ],
1093 )
1094 }
1095
1096 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1098 Self::commit_corruption()
1099 }
1100
1101 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1103 Self::store_unsupported()
1104 }
1105
1106 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1108 Self::store_unsupported()
1109 }
1110
1111 pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
1113 Self::store_corruption()
1114 }
1115
1116 #[cold]
1118 #[inline(never)]
1119 pub(crate) fn index_corruption() -> Self {
1120 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1121 }
1122
1123 pub(crate) fn index_unique_validation_corruption() -> Self {
1125 Self::index_plan_index_corruption()
1126 }
1127
1128 pub(crate) fn structural_index_entry_corruption() -> Self {
1130 Self::index_plan_index_corruption()
1131 }
1132
1133 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1135 Self::index_invariant()
1136 }
1137
1138 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1140 Self::index_plan_serialize_corruption()
1141 }
1142
1143 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1145 Self::index_plan_serialize_corruption()
1146 }
1147
1148 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1150 Self::index_plan_serialize_corruption()
1151 }
1152
1153 pub(crate) fn index_unique_validation_row_required() -> Self {
1155 Self::index_plan_store_corruption()
1156 }
1157
1158 pub(crate) fn index_only_predicate_component_required() -> Self {
1160 Self::index_invariant()
1161 }
1162
1163 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1165 Self::index_invariant()
1166 }
1167
1168 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1170 Self::index_invariant()
1171 }
1172
1173 pub(crate) fn index_scan_key_corrupted_during(
1175 _context: &'static str,
1176 _err: impl Sized,
1177 ) -> Self {
1178 Self::index_corruption()
1179 }
1180
1181 pub(crate) fn index_projection_component_required(
1183 _index_name: &str,
1184 _component_index: usize,
1185 ) -> Self {
1186 Self::index_invariant()
1187 }
1188
1189 pub(crate) fn index_entry_decode_failed() -> Self {
1191 Self::index_corruption()
1192 }
1193
1194 pub(crate) fn serialize_corruption() -> Self {
1196 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1197 }
1198
1199 pub(crate) fn persisted_row_decode_corruption() -> Self {
1201 Self::serialize_corruption()
1202 }
1203
1204 pub(crate) fn persisted_row_layout_outside_accepted_window(
1206 row_layout: u32,
1207 history_floor: u32,
1208 current_layout: u32,
1209 ) -> Self {
1210 Self::with_diagnostic_facts(
1211 ErrorClass::Corruption,
1212 ErrorOrigin::Serialize,
1213 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1214 boundary:
1215 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1216 }),
1217 vec![
1218 (
1219 diagnostic_code::DiagnosticFactTag::RowLayout,
1220 u64::from(row_layout),
1221 ),
1222 (
1223 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1224 u64::from(history_floor),
1225 ),
1226 (
1227 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1228 u64::from(current_layout),
1229 ),
1230 ],
1231 )
1232 }
1233
1234 pub(crate) fn persisted_row_slot_count_mismatch(
1236 row_layout: u32,
1237 expected_slot_count: usize,
1238 actual_slot_count: usize,
1239 ) -> Self {
1240 Self::with_diagnostic_facts(
1241 ErrorClass::Corruption,
1242 ErrorOrigin::Serialize,
1243 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1244 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1245 }),
1246 vec![
1247 (
1248 diagnostic_code::DiagnosticFactTag::RowLayout,
1249 u64::from(row_layout),
1250 ),
1251 (
1252 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1253 expected_slot_count as u64,
1254 ),
1255 (
1256 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1257 actual_slot_count as u64,
1258 ),
1259 ],
1260 )
1261 }
1262
1263 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1265 Self::persisted_row_field_decode_corruption(field_name)
1266 }
1267
1268 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1270 Self::persisted_row_decode_corruption()
1271 }
1272
1273 pub(crate) fn persisted_row_field_kind_decode_failed(
1275 field_name: &str,
1276 _field_kind: impl fmt::Debug,
1277 _detail: impl Sized,
1278 ) -> Self {
1279 Self::persisted_row_field_decode_corruption(field_name)
1280 }
1281
1282 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1284 Self::persisted_row_field_decode_corruption(field_name)
1285 }
1286
1287 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1289 Self::persisted_row_field_decode_corruption(field_name)
1290 }
1291
1292 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1294 Self::persisted_row_field_decode_corruption(field_name)
1295 }
1296
1297 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1299 Self::persisted_row_field_decode_corruption(field_name)
1300 }
1301
1302 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1304 Self::persisted_row_field_decode_corruption(field_name)
1305 }
1306
1307 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1309 Self::index_invariant()
1310 }
1311
1312 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1314 _model_path: &str,
1315 _slot: usize,
1316 ) -> Self {
1317 Self::index_invariant()
1318 }
1319
1320 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1322 _data_key: impl fmt::Debug,
1323 _detail: impl Sized,
1324 ) -> Self {
1325 Self::persisted_row_decode_corruption()
1326 }
1327
1328 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1330 Self::persisted_row_decode_corruption()
1331 }
1332
1333 pub(crate) fn persisted_row_key_mismatch() -> Self {
1335 Self::store_corruption()
1336 }
1337
1338 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1340 Self::persisted_row_field_decode_corruption(field_name)
1341 }
1342
1343 pub(crate) fn reverse_index_ordinal_overflow(
1345 _source_path: &str,
1346 _field_name: &str,
1347 _target_path: &str,
1348 _detail: impl Sized,
1349 ) -> Self {
1350 Self::index_internal()
1351 }
1352
1353 pub(crate) fn reverse_index_entry_corrupted(
1355 _source_path: &str,
1356 _field_name: &str,
1357 _target_path: &str,
1358 _index_key: impl fmt::Debug,
1359 _detail: impl Sized,
1360 ) -> Self {
1361 Self::index_corruption()
1362 }
1363
1364 pub(crate) fn relation_target_store_missing(
1366 _source_path: &str,
1367 _field_name: &str,
1368 _target_path: &str,
1369 _store_path: &str,
1370 _detail: impl Sized,
1371 ) -> Self {
1372 Self::executor_internal()
1373 }
1374
1375 pub(crate) fn relation_target_primary_key_arity_mismatch(
1377 expected_arity: usize,
1378 actual_arity: usize,
1379 ) -> Self {
1380 Self::with_diagnostic_facts(
1381 ErrorClass::Internal,
1382 ErrorOrigin::Executor,
1383 None,
1384 vec![
1385 (
1386 diagnostic_code::DiagnosticFactTag::ComponentKind,
1387 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1388 ),
1389 (
1390 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1391 expected_arity as u64,
1392 ),
1393 (
1394 diagnostic_code::DiagnosticFactTag::ActualArity,
1395 actual_arity as u64,
1396 ),
1397 ],
1398 )
1399 }
1400
1401 pub(crate) fn relation_target_key_decode_failed(
1403 _context_label: &str,
1404 _source_path: &str,
1405 _field_name: &str,
1406 _target_path: &str,
1407 _detail: impl Sized,
1408 ) -> Self {
1409 Self::identity_corruption()
1410 }
1411
1412 pub(crate) fn relation_target_entity_mismatch(
1414 _context_label: &str,
1415 _source_path: &str,
1416 _field_name: &str,
1417 _target_path: &str,
1418 _target_entity_name: &str,
1419 expected_tag: u64,
1420 actual_tag: u64,
1421 ) -> Self {
1422 Self::with_diagnostic_facts(
1423 ErrorClass::Corruption,
1424 ErrorOrigin::Store,
1425 None,
1426 vec![
1427 (
1428 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1429 expected_tag,
1430 ),
1431 (
1432 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1433 actual_tag,
1434 ),
1435 ],
1436 )
1437 }
1438
1439 pub(crate) fn relation_source_row_decode_failed(
1441 _source_path: &str,
1442 _field_name: &str,
1443 _target_path: &str,
1444 _detail: impl Sized,
1445 ) -> Self {
1446 Self::persisted_row_decode_corruption()
1447 }
1448
1449 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1451 _source_path: &str,
1452 _field_name: &str,
1453 _target_path: &str,
1454 ) -> Self {
1455 Self::persisted_row_decode_corruption()
1456 }
1457
1458 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1460 Self::persisted_row_decode_corruption()
1461 }
1462
1463 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1465 Self::index_corruption()
1466 }
1467
1468 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1470 Self::index_corruption()
1471 }
1472
1473 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1475 Self::index_corruption()
1476 }
1477
1478 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1480 Self::index_corruption()
1481 }
1482
1483 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1485 Self::index_corruption()
1486 }
1487
1488 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1490 Self::index_corruption()
1491 }
1492
1493 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1495 Self::index_corruption()
1496 }
1497
1498 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1500 Self::index_corruption()
1501 }
1502
1503 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1505 Self::index_corruption()
1506 }
1507
1508 pub(crate) fn identity_corruption() -> Self {
1510 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1511 }
1512
1513 pub(crate) fn identity_state_corruption() -> Self {
1515 Self::identity_corruption()
1516 }
1517
1518 pub(crate) fn identity_state_conflict() -> Self {
1520 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1521 }
1522
1523 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1525 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1526 }
1527
1528 pub(crate) fn identity_exhausted() -> Self {
1530 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1531 }
1532
1533 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1535 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1536 }
1537
1538 #[cold]
1540 #[inline(never)]
1541 pub(crate) fn store_unsupported() -> Self {
1542 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1543 }
1544
1545 pub(crate) fn schema_application_conflict() -> Self {
1547 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1548 }
1549
1550 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1552 let class = match reason.diagnostic_code() {
1553 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1554 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1555 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1556 _ => ErrorClass::Internal,
1557 };
1558 Self {
1559 class,
1560 origin: ErrorOrigin::Store,
1561 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1562 }
1563 }
1564
1565 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1567 Self {
1568 class: ErrorClass::Unsupported,
1569 origin: ErrorOrigin::Store,
1570 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1571 }
1572 }
1573
1574 #[cfg(feature = "sql")]
1576 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1577 Self {
1578 class: ErrorClass::Unsupported,
1579 origin: ErrorOrigin::Store,
1580 detail: Some(ErrorDetail::Store(
1581 StoreError::SchemaDdlRewriteRequiresMigration,
1582 )),
1583 }
1584 }
1585
1586 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1588 Self {
1589 class: ErrorClass::Unsupported,
1590 origin: ErrorOrigin::Store,
1591 detail: Some(ErrorDetail::Store(
1592 StoreError::JournalMutationRevisionExhausted,
1593 )),
1594 }
1595 }
1596
1597 pub(crate) fn schema_transition_budget_exceeded(
1599 resource: SchemaTransitionBudgetResource,
1600 ) -> Self {
1601 Self {
1602 class: ErrorClass::Unsupported,
1603 origin: ErrorOrigin::Store,
1604 detail: Some(ErrorDetail::Store(
1605 StoreError::SchemaTransitionBudgetExceeded { resource },
1606 )),
1607 }
1608 }
1609
1610 pub(crate) fn unsupported_entity_tag_in_data_store(
1612 _entity_tag: crate::types::EntityTag,
1613 ) -> Self {
1614 Self::store_unsupported()
1615 }
1616
1617 #[cfg(not(test))]
1619 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1620 Self::store_internal()
1621 }
1622
1623 pub(crate) fn index_unsupported() -> Self {
1625 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1626 }
1627
1628 pub(crate) fn index_component_exceeds_max_size_at(
1630 entity_tag: u64,
1631 physical_generation: u64,
1632 component_index: usize,
1633 actual_length: usize,
1634 limit: usize,
1635 ) -> Self {
1636 Self::with_diagnostic_facts(
1637 ErrorClass::Unsupported,
1638 ErrorOrigin::Index,
1639 None,
1640 vec![
1641 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1642 (
1643 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1644 physical_generation,
1645 ),
1646 (
1647 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1648 component_index as u64,
1649 ),
1650 (
1651 diagnostic_code::DiagnosticFactTag::ComponentKind,
1652 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1653 ),
1654 (
1655 diagnostic_code::DiagnosticFactTag::ActualLength,
1656 actual_length as u64,
1657 ),
1658 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1659 ],
1660 )
1661 }
1662
1663 pub(crate) fn index_component_exceeds_max_size() -> Self {
1666 Self::index_unsupported()
1667 }
1668
1669 pub(crate) fn serialize_unsupported() -> Self {
1671 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1672 }
1673
1674 pub(crate) fn cursor_invalid_continuation() -> Self {
1676 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1677 }
1678
1679 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1681 Self::new(
1682 ErrorClass::IncompatiblePersistedFormat,
1683 ErrorOrigin::Serialize,
1684 )
1685 }
1686
1687 #[cfg(feature = "sql")]
1690 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1691 Self {
1692 class: ErrorClass::Unsupported,
1693 origin: ErrorOrigin::Query,
1694 detail: Some(ErrorDetail::Query(
1695 QueryErrorDetail::UnsupportedSqlFeature { feature },
1696 )),
1697 }
1698 }
1699
1700 #[cfg(feature = "sql")]
1703 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1704 Self {
1705 class: ErrorClass::Unsupported,
1706 origin: ErrorOrigin::Query,
1707 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1708 }
1709 }
1710
1711 #[cfg(feature = "sql")]
1713 pub(crate) fn query_sql_lowering_with_facts(
1714 reason: diagnostic_code::SqlLoweringCode,
1715 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1716 ) -> Self {
1717 Self::with_diagnostic_facts(
1718 ErrorClass::Unsupported,
1719 ErrorOrigin::Query,
1720 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1721 facts,
1722 )
1723 }
1724
1725 pub(crate) fn query_unsupported_projection(
1728 reason: diagnostic_code::QueryProjectionCode,
1729 ) -> Self {
1730 Self {
1731 class: ErrorClass::Unsupported,
1732 origin: ErrorOrigin::Query,
1733 detail: Some(ErrorDetail::Query(
1734 QueryErrorDetail::UnsupportedProjection { reason },
1735 )),
1736 }
1737 }
1738
1739 pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1741 Self {
1742 class: ErrorClass::Unsupported,
1743 origin: ErrorOrigin::Query,
1744 detail: Some(ErrorDetail::Query(
1745 QueryErrorDetail::UnknownAggregateTargetField,
1746 )),
1747 }
1748 }
1749
1750 #[cfg(feature = "sql")]
1753 pub(crate) fn query_sql_surface_mismatch(
1754 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1755 ) -> Self {
1756 Self {
1757 class: ErrorClass::Unsupported,
1758 origin: ErrorOrigin::Query,
1759 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1760 mismatch,
1761 })),
1762 }
1763 }
1764
1765 pub(crate) fn query_sql_write_boundary(
1767 boundary: diagnostic_code::SqlWriteBoundaryCode,
1768 ) -> Self {
1769 Self {
1770 class: ErrorClass::Unsupported,
1771 origin: ErrorOrigin::Query,
1772 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1773 boundary,
1774 })),
1775 }
1776 }
1777
1778 pub(crate) fn query_sql_write_boundary_with_facts(
1780 boundary: diagnostic_code::SqlWriteBoundaryCode,
1781 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1782 ) -> Self {
1783 Self::with_diagnostic_facts(
1784 ErrorClass::Unsupported,
1785 ErrorOrigin::Query,
1786 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1787 facts,
1788 )
1789 }
1790
1791 pub fn store_not_found(_key: impl Sized) -> Self {
1792 Self {
1793 class: ErrorClass::NotFound,
1794 origin: ErrorOrigin::Store,
1795 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1796 }
1797 }
1798
1799 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1801 Self::store_unsupported()
1802 }
1803
1804 #[cold]
1806 #[inline(never)]
1807 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1808 Self::new(ErrorClass::Corruption, origin)
1809 }
1810
1811 #[cold]
1813 #[inline(never)]
1814 pub(crate) fn index_plan_index_corruption() -> Self {
1815 Self::index_plan_corruption(ErrorOrigin::Index)
1816 }
1817
1818 #[cold]
1820 #[inline(never)]
1821 pub(crate) fn index_plan_store_corruption() -> Self {
1822 Self::index_plan_corruption(ErrorOrigin::Store)
1823 }
1824
1825 #[cold]
1827 #[inline(never)]
1828 pub(crate) fn index_plan_serialize_corruption() -> Self {
1829 Self::index_plan_corruption(ErrorOrigin::Serialize)
1830 }
1831
1832 #[cfg(test)]
1834 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1835 Self::new(ErrorClass::InvariantViolation, origin)
1836 }
1837
1838 #[cfg(test)]
1840 pub(crate) fn index_plan_store_invariant() -> Self {
1841 Self::index_plan_invariant(ErrorOrigin::Store)
1842 }
1843
1844 pub(crate) fn index_conflict() -> Self {
1850 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1851 }
1852}
1853
1854impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1855 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1856 Self {
1857 class: ErrorClass::Unsupported,
1858 origin: ErrorOrigin::Query,
1859 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1860 reason,
1861 })),
1862 }
1863 }
1864}
1865
1866impl fmt::Debug for InternalError {
1867 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1868 fmt_compact_diagnostic(
1869 f,
1870 self.diagnostic_code(),
1871 self.detail
1872 .as_ref()
1873 .and_then(ErrorDetail::diagnostic_detail),
1874 )
1875 }
1876}
1877
1878impl fmt::Display for InternalError {
1879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1880 f.write_str(self.message())
1881 }
1882}
1883
1884impl std::error::Error for InternalError {}
1885
1886#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1895pub enum ConstraintValuePathComponent {
1896 RootField { field_id: u32 },
1898
1899 RecordMember {
1901 composite_type_id: u32,
1902 member_id: u32,
1903 },
1904
1905 TupleElement {
1907 composite_type_id: u32,
1908 ordinal: u32,
1909 },
1910
1911 Newtype { composite_type_id: u32 },
1913
1914 EnumVariant { enum_type_id: u32, variant_id: u32 },
1916
1917 ListElement { index: u32 },
1919
1920 SetElement { index: u32 },
1922
1923 MapEntryKey { index: u32 },
1925
1926 MapEntryValue { index: u32 },
1928}
1929
1930impl fmt::Display for ConstraintValuePathComponent {
1931 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1932 match self {
1933 Self::RootField { field_id } => write!(f, "field#{field_id}"),
1934 Self::RecordMember {
1935 composite_type_id,
1936 member_id,
1937 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
1938 Self::TupleElement {
1939 composite_type_id,
1940 ordinal,
1941 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
1942 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
1943 Self::EnumVariant {
1944 enum_type_id,
1945 variant_id,
1946 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
1947 Self::ListElement { index } => write!(f, "list[{index}]"),
1948 Self::SetElement { index } => write!(f, "set[{index}]"),
1949 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
1950 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
1951 }
1952 }
1953}
1954
1955#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1962pub struct ConstraintValuePath {
1963 components: Vec<ConstraintValuePathComponent>,
1964}
1965
1966impl ConstraintValuePath {
1967 #[must_use]
1969 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
1970 Self { components }
1971 }
1972
1973 #[must_use]
1975 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
1976 self.components.as_slice()
1977 }
1978}
1979
1980impl fmt::Display for ConstraintValuePath {
1981 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982 for (ordinal, component) in self.components.iter().enumerate() {
1983 if ordinal != 0 {
1984 f.write_str("/")?;
1985 }
1986 component.fmt(f)?;
1987 }
1988 Ok(())
1989 }
1990}
1991
1992#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2001pub struct ConstraintValidationFindingOutput {
2002 accepted_schema_fingerprint: [u8; 16],
2003 entity_tag: u64,
2004 constraint_id: u32,
2005 primary_key: Vec<u8>,
2006 field_ids: Vec<u32>,
2007 value_path: Option<ConstraintValuePath>,
2008 error_code: u16,
2009}
2010
2011impl ConstraintValidationFindingOutput {
2012 #[must_use]
2014 pub(crate) const fn new(
2015 accepted_schema_fingerprint: [u8; 16],
2016 entity_tag: u64,
2017 constraint_id: u32,
2018 primary_key: Vec<u8>,
2019 field_ids: Vec<u32>,
2020 value_path: Option<ConstraintValuePath>,
2021 error_code: u16,
2022 ) -> Self {
2023 Self {
2024 accepted_schema_fingerprint,
2025 entity_tag,
2026 constraint_id,
2027 primary_key,
2028 field_ids,
2029 value_path,
2030 error_code,
2031 }
2032 }
2033
2034 #[must_use]
2036 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2037 self.accepted_schema_fingerprint
2038 }
2039
2040 #[must_use]
2042 pub const fn entity_tag(&self) -> u64 {
2043 self.entity_tag
2044 }
2045
2046 #[must_use]
2048 pub const fn constraint_id(&self) -> u32 {
2049 self.constraint_id
2050 }
2051
2052 #[must_use]
2054 pub const fn primary_key(&self) -> &[u8] {
2055 self.primary_key.as_slice()
2056 }
2057
2058 #[must_use]
2060 pub const fn field_ids(&self) -> &[u32] {
2061 self.field_ids.as_slice()
2062 }
2063
2064 #[must_use]
2066 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2067 self.value_path.as_ref()
2068 }
2069
2070 #[must_use]
2072 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2073 diagnostic_code::ErrorCode::from_raw(self.error_code)
2074 }
2075
2076 #[must_use]
2078 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2079 self.error_code().class()
2080 }
2081}
2082
2083#[derive(Clone)]
2085pub(crate) struct AcceptedConstraintFactContext {
2086 fingerprint_method: u8,
2087 accepted_schema_fingerprint: [u8; 16],
2088 entity_tag: u64,
2089 constraint_id: u32,
2090 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2091 mutation: Option<MutationDiagnosticContext>,
2092 value_path: Option<ConstraintValuePath>,
2093}
2094
2095impl AcceptedConstraintFactContext {
2096 #[must_use]
2097 pub(crate) fn write_admission(
2098 fingerprint_method: u8,
2099 accepted_schema_fingerprint: [u8; 16],
2100 entity_tag: u64,
2101 constraint_id: u32,
2102 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2103 mutation: Option<MutationDiagnosticContext>,
2104 value_path: Option<ConstraintValuePath>,
2105 ) -> Self {
2106 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2107 Self {
2108 fingerprint_method,
2109 accepted_schema_fingerprint,
2110 entity_tag,
2111 constraint_id,
2112 constraint_kind,
2113 mutation,
2114 value_path,
2115 }
2116 }
2117
2118 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2119 let high = u64::from_be_bytes([
2120 self.accepted_schema_fingerprint[0],
2121 self.accepted_schema_fingerprint[1],
2122 self.accepted_schema_fingerprint[2],
2123 self.accepted_schema_fingerprint[3],
2124 self.accepted_schema_fingerprint[4],
2125 self.accepted_schema_fingerprint[5],
2126 self.accepted_schema_fingerprint[6],
2127 self.accepted_schema_fingerprint[7],
2128 ]);
2129 let low = u64::from_be_bytes([
2130 self.accepted_schema_fingerprint[8],
2131 self.accepted_schema_fingerprint[9],
2132 self.accepted_schema_fingerprint[10],
2133 self.accepted_schema_fingerprint[11],
2134 self.accepted_schema_fingerprint[12],
2135 self.accepted_schema_fingerprint[13],
2136 self.accepted_schema_fingerprint[14],
2137 self.accepted_schema_fingerprint[15],
2138 ]);
2139 let path_len = self
2140 .value_path
2141 .as_ref()
2142 .map_or(0, |path| path.components().len());
2143 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2144 1 + usize::from(mutation.batch_position.is_some())
2145 });
2146 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2147 facts.push((
2148 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2149 u64::from(self.fingerprint_method),
2150 ));
2151 facts.push((
2152 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2153 high,
2154 ));
2155 facts.push((
2156 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2157 low,
2158 ));
2159 facts.push((
2160 diagnostic_code::DiagnosticFactTag::EntityTag,
2161 self.entity_tag,
2162 ));
2163 facts.push((
2164 diagnostic_code::DiagnosticFactTag::ConstraintId,
2165 u64::from(self.constraint_id),
2166 ));
2167 facts.push((
2168 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2169 self.constraint_kind.raw(),
2170 ));
2171 facts.push((
2172 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2173 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2174 ));
2175 if let Some(mutation) = self.mutation {
2176 mutation.append_operation_facts(&mut facts);
2177 }
2178 if let Some(path) = self.value_path {
2179 for component in path.components {
2180 facts.push(constraint_value_path_fact(component));
2181 }
2182 }
2183 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2184 facts
2185 }
2186}
2187
2188fn constraint_value_path_fact(
2189 component: ConstraintValuePathComponent,
2190) -> (diagnostic_code::DiagnosticFactTag, u64) {
2191 use diagnostic_code::DiagnosticFactTag;
2192 match component {
2193 ConstraintValuePathComponent::RootField { field_id } => {
2194 (DiagnosticFactTag::RootField, u64::from(field_id))
2195 }
2196 ConstraintValuePathComponent::RecordMember {
2197 composite_type_id,
2198 member_id,
2199 } => (
2200 DiagnosticFactTag::RecordMember,
2201 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2202 ),
2203 ConstraintValuePathComponent::TupleElement {
2204 composite_type_id,
2205 ordinal,
2206 } => (
2207 DiagnosticFactTag::TupleElement,
2208 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2209 ),
2210 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2211 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2212 }
2213 ConstraintValuePathComponent::EnumVariant {
2214 enum_type_id,
2215 variant_id,
2216 } => (
2217 DiagnosticFactTag::EnumVariant,
2218 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2219 ),
2220 ConstraintValuePathComponent::ListElement { index } => {
2221 (DiagnosticFactTag::ListElement, u64::from(index))
2222 }
2223 ConstraintValuePathComponent::SetElement { index } => {
2224 (DiagnosticFactTag::SetElement, u64::from(index))
2225 }
2226 ConstraintValuePathComponent::MapEntryKey { index } => {
2227 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2228 }
2229 ConstraintValuePathComponent::MapEntryValue { index } => {
2230 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2231 }
2232 }
2233}
2234
2235pub enum ErrorDetail {
2243 DiagnosticFacts(Box<DiagnosticFactDetail>),
2245 Executor(ExecutorErrorDetail),
2247 Store(StoreError),
2248 Query(QueryErrorDetail),
2249 Recovery(RecoveryErrorDetail),
2250 }
2253
2254pub enum ExecutorErrorDetail {
2256 MutationRequiredFieldMissing,
2258 MutationManagedTimestampRegression,
2260 MutationDatabaseOwnedFieldExplicit,
2262 MutationBatchEmpty,
2264 MutationBatchTooManyItems,
2266 MutationBatchStagedBytesExceeded,
2268 MutationBatchResultBytesExceeded,
2270 MutationBatchEntityMismatch,
2272 MutationBatchDuplicateKey,
2274 AcceptedRowConstraintProgramCorrupt,
2276}
2277
2278pub enum RecoveryErrorDetail {
2285 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2286
2287 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2288}
2289
2290#[derive(Clone, Copy, Eq, PartialEq)]
2292pub enum RecoveryFormatMarkerError {
2293 Magic,
2294 Checksum,
2295 State,
2296}
2297
2298impl RecoveryFormatMarkerError {
2299 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2300 match self {
2301 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2302 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2303 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2304 }
2305 }
2306}
2307
2308pub enum StoreError {
2316 NotFound,
2317
2318 Corrupt,
2319
2320 InvariantViolation,
2321
2322 SchemaDdlPublicationRaceLost,
2323
2324 SchemaDdlRewriteRequiresMigration,
2325
2326 SchemaMigration {
2327 reason: diagnostic_code::SchemaMigrationCode,
2328 },
2329
2330 SchemaRowLayoutVersionExhausted,
2331
2332 JournalMutationRevisionExhausted,
2333
2334 SchemaTransitionBudgetExceeded {
2335 resource: SchemaTransitionBudgetResource,
2336 },
2337
2338 SchemaGeneratedFieldAfterDdlField,
2340
2341 SchemaGeneratedConstraintActivationStale,
2343}
2344
2345pub enum QueryErrorDetail {
2352 NumericOverflow,
2353
2354 NumericNotRepresentable,
2355
2356 UnsupportedSqlFeature {
2357 feature: diagnostic_code::SqlFeatureCode,
2358 },
2359
2360 SqlLowering {
2361 reason: diagnostic_code::SqlLoweringCode,
2362 },
2363
2364 UnsupportedProjection {
2365 reason: diagnostic_code::QueryProjectionCode,
2366 },
2367
2368 UnknownAggregateTargetField,
2369
2370 ResultShapeMismatch {
2371 reason: diagnostic_code::QueryResultShapeCode,
2372 },
2373
2374 QueryReadAdmission {
2375 reason: diagnostic_code::QueryReadAdmissionCode,
2376 },
2377
2378 SqlSurfaceMismatch {
2379 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2380 },
2381
2382 SqlWriteBoundary {
2383 boundary: diagnostic_code::SqlWriteBoundaryCode,
2384 },
2385
2386 SchemaDdlAdmission {
2387 error: SchemaDdlAdmissionError,
2388 },
2389
2390 StaleSchemaRevision,
2391}
2392
2393impl fmt::Display for QueryErrorDetail {
2394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2395 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2396 }
2397}
2398
2399impl std::error::Error for QueryErrorDetail {}
2400
2401#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2409pub enum SchemaTransitionBudgetResource {
2410 DeletionKeys,
2412 ProjectionEntries,
2414 ProjectionWorkUnits,
2416 SourceRows,
2418 SourceRowBytes,
2420 StagedRawBytes,
2422}
2423
2424#[derive(Clone, Copy, Eq, PartialEq)]
2433pub enum SchemaDdlAdmissionError {
2434 MissingExpectedSchemaVersion,
2435
2436 MissingNextSchemaVersion,
2437
2438 StaleExpectedSchemaVersion,
2439
2440 InvalidExpectedSchemaVersion,
2441
2442 InvalidNextSchemaVersion,
2443
2444 AcceptedSchemaChangeWithoutVersionBump,
2445
2446 EmptyVersionBump,
2447
2448 VersionGap,
2449
2450 VersionRollback,
2451
2452 FingerprintMethodMismatch,
2453
2454 UnsupportedTransitionClass,
2455
2456 PhysicalRunnerMissing,
2457
2458 ValidationFailed,
2459
2460 PublicationRaceLost,
2461
2462 InvalidAddColumnDefault,
2463
2464 InvalidAlterColumnDefault,
2465
2466 RowLayoutVersionExhausted,
2467
2468 GeneratedIndexDropRejected,
2469
2470 SchemaRewriteRequiresMigration,
2471
2472 SchemaTransitionBudgetExceeded {
2473 resource: SchemaTransitionBudgetResource,
2474 },
2475
2476 GeneratedFieldDefaultChangeRejected,
2477
2478 GeneratedFieldNullabilityChangeRejected,
2479}
2480
2481impl fmt::Display for SchemaDdlAdmissionError {
2482 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2483 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2484 }
2485}
2486
2487impl std::error::Error for SchemaDdlAdmissionError {}
2488
2489impl fmt::Debug for ErrorDetail {
2490 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2491 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2492 }
2493}
2494
2495impl fmt::Debug for ExecutorErrorDetail {
2496 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2497 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2498 }
2499}
2500
2501impl fmt::Debug for StoreError {
2502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2503 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2504 }
2505}
2506
2507impl fmt::Debug for QueryErrorDetail {
2508 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2509 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2510 }
2511}
2512
2513impl fmt::Debug for RecoveryErrorDetail {
2514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2515 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2516 }
2517}
2518
2519impl fmt::Debug for RecoveryFormatMarkerError {
2520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2521 fmt_compact_diagnostic(
2522 f,
2523 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2524 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2525 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2526 }),
2527 )
2528 }
2529}
2530
2531impl fmt::Debug for SchemaDdlAdmissionError {
2532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2533 fmt_compact_diagnostic(
2534 f,
2535 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2536 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2537 reason: self.diagnostic_code(),
2538 }),
2539 )
2540 }
2541}
2542
2543fn fmt_compact_diagnostic(
2544 f: &mut fmt::Formatter<'_>,
2545 code: diagnostic_code::DiagnosticCode,
2546 detail: Option<diagnostic_code::DiagnosticDetail>,
2547) -> fmt::Result {
2548 write!(
2549 f,
2550 "{}",
2551 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2552 )
2553}
2554
2555impl ErrorDetail {
2556 #[must_use]
2558 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2559 match self {
2560 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2561 Self::Executor(error) => error.diagnostic_code(),
2562 Self::Store(error) => error.diagnostic_code(),
2563 Self::Query(error) => error.diagnostic_code(),
2564 Self::Recovery(error) => error.diagnostic_code(),
2565 }
2566 }
2567
2568 #[must_use]
2570 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2571 match self {
2572 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2573 Self::Executor(error) => error.diagnostic_detail(),
2574 Self::Store(error) => error.diagnostic_detail(),
2575 Self::Query(error) => error.diagnostic_detail(),
2576 Self::Recovery(error) => error.diagnostic_detail(),
2577 }
2578 }
2579
2580 #[must_use]
2582 #[cold]
2583 #[inline(never)]
2584 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2585 match self {
2586 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2587 Self::Executor(error) => error.diagnostic_facts(),
2588 Self::Query(error) => error.diagnostic_facts(),
2589 Self::Recovery(error) => error.diagnostic_facts(),
2590 Self::Store(_) => Vec::new(),
2591 }
2592 }
2593}
2594
2595impl ExecutorErrorDetail {
2596 #[must_use]
2598 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2599 match self {
2600 Self::MutationRequiredFieldMissing
2601 | Self::MutationDatabaseOwnedFieldExplicit
2602 | Self::MutationBatchEmpty
2603 | Self::MutationBatchTooManyItems
2604 | Self::MutationBatchStagedBytesExceeded
2605 | Self::MutationBatchResultBytesExceeded => {
2606 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2607 }
2608 Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2609 diagnostic_code::DiagnosticCode::RuntimeConflict
2610 }
2611 Self::MutationManagedTimestampRegression => {
2612 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2613 }
2614 Self::AcceptedRowConstraintProgramCorrupt => {
2615 diagnostic_code::DiagnosticCode::RuntimeCorruption
2616 }
2617 }
2618 }
2619
2620 #[must_use]
2622 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2623 match self {
2624 Self::MutationRequiredFieldMissing => {
2625 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2626 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2627 })
2628 }
2629 Self::MutationDatabaseOwnedFieldExplicit => {
2630 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2631 boundary:
2632 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2633 })
2634 }
2635 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2636 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2637 }),
2638 Self::MutationBatchTooManyItems => {
2639 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2640 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2641 })
2642 }
2643 Self::MutationBatchStagedBytesExceeded => {
2644 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2645 boundary:
2646 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2647 })
2648 }
2649 Self::MutationBatchResultBytesExceeded => {
2650 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2651 boundary:
2652 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2653 })
2654 }
2655 Self::MutationBatchEntityMismatch => {
2656 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2657 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2658 })
2659 }
2660 Self::MutationBatchDuplicateKey => {
2661 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2662 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2663 })
2664 }
2665 Self::MutationManagedTimestampRegression => {
2666 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2667 boundary:
2668 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2669 })
2670 }
2671 Self::AcceptedRowConstraintProgramCorrupt => {
2672 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2673 boundary:
2674 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2675 })
2676 }
2677 }
2678 }
2679
2680 #[must_use]
2682 #[cold]
2683 #[inline(never)]
2684 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2685 Vec::new()
2686 }
2687}
2688
2689impl RecoveryErrorDetail {
2690 #[must_use]
2692 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2693 match self {
2694 Self::UnsupportedFormatVersion { .. } => {
2695 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2696 }
2697 Self::MalformedFormatMarker { .. } => {
2698 diagnostic_code::DiagnosticCode::RuntimeCorruption
2699 }
2700 }
2701 }
2702
2703 #[must_use]
2705 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2706 let kind = match self {
2707 Self::UnsupportedFormatVersion { .. } => {
2708 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2709 }
2710 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2711 };
2712
2713 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2714 }
2715
2716 #[must_use]
2718 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2719 match self {
2720 Self::UnsupportedFormatVersion { found, required } => {
2721 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2722 facts.push((
2723 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2724 u64::from(*required),
2725 ));
2726 if let Some(found) = found {
2727 facts.push((
2728 diagnostic_code::DiagnosticFactTag::ActualVersion,
2729 u64::from(*found),
2730 ));
2731 }
2732 facts
2733 }
2734 Self::MalformedFormatMarker { reason } => vec![(
2735 diagnostic_code::DiagnosticFactTag::DecodeReason,
2736 reason.diagnostic_decode_reason().raw(),
2737 )],
2738 }
2739 }
2740}
2741
2742impl StoreError {
2743 #[must_use]
2745 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2746 match self {
2747 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2748 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2749 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2750 Self::SchemaDdlPublicationRaceLost
2751 | Self::SchemaDdlRewriteRequiresMigration
2752 | Self::SchemaRowLayoutVersionExhausted
2753 | Self::SchemaTransitionBudgetExceeded { .. } => {
2754 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2755 }
2756 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2757 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2758 }
2759 Self::SchemaGeneratedConstraintActivationStale => {
2760 diagnostic_code::DiagnosticCode::RuntimeConflict
2761 }
2762 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2763 }
2764 }
2765
2766 #[must_use]
2768 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2769 match self {
2770 Self::SchemaDdlPublicationRaceLost => {
2771 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2772 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2773 })
2774 }
2775 Self::SchemaDdlRewriteRequiresMigration => {
2776 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2777 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2778 })
2779 }
2780 Self::SchemaMigration { reason } => {
2781 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2782 }
2783 Self::SchemaRowLayoutVersionExhausted => {
2784 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2785 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2786 })
2787 }
2788 Self::JournalMutationRevisionExhausted => {
2789 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2790 boundary:
2791 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2792 })
2793 }
2794 Self::SchemaTransitionBudgetExceeded { .. } => {
2795 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2796 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2797 })
2798 }
2799 Self::SchemaGeneratedFieldAfterDdlField => {
2800 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2801 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2802 })
2803 }
2804 Self::SchemaGeneratedConstraintActivationStale => {
2805 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2806 boundary:
2807 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2808 })
2809 }
2810 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2811 }
2812 }
2813}
2814
2815impl QueryErrorDetail {
2816 #[must_use]
2818 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2819 match self {
2820 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2821 Self::NumericNotRepresentable => {
2822 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2823 }
2824 Self::UnsupportedSqlFeature { .. } => {
2825 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2826 }
2827 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2828 Self::UnsupportedProjection { .. } => {
2829 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2830 }
2831 Self::UnknownAggregateTargetField => {
2832 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2833 }
2834 Self::ResultShapeMismatch { .. } => {
2835 diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2836 }
2837 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2838 Self::SqlSurfaceMismatch { .. } => {
2839 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2840 }
2841 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2842 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2843 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2844 }
2845 }
2846
2847 #[must_use]
2849 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2850 match self {
2851 Self::UnsupportedSqlFeature { feature } => {
2852 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2853 }
2854 Self::SqlLowering { reason } => {
2855 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2856 }
2857 Self::UnsupportedProjection { reason } => {
2858 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2859 }
2860 Self::ResultShapeMismatch { reason } => {
2861 Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2862 }
2863 Self::QueryReadAdmission { reason } => {
2864 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2865 }
2866 Self::SqlSurfaceMismatch { mismatch } => {
2867 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2868 mismatch: *mismatch,
2869 })
2870 }
2871 Self::SqlWriteBoundary { boundary } => {
2872 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2873 boundary: *boundary,
2874 })
2875 }
2876 Self::SchemaDdlAdmission { error } => {
2877 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2878 reason: error.diagnostic_code(),
2879 })
2880 }
2881 Self::NumericOverflow
2882 | Self::NumericNotRepresentable
2883 | Self::UnknownAggregateTargetField
2884 | Self::StaleSchemaRevision => None,
2885 }
2886 }
2887
2888 #[must_use]
2890 #[cold]
2891 #[inline(never)]
2892 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2893 Vec::new()
2894 }
2895}
2896
2897impl SchemaDdlAdmissionError {
2898 #[must_use]
2900 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2901 match self {
2902 Self::MissingExpectedSchemaVersion => {
2903 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2904 }
2905 Self::MissingNextSchemaVersion => {
2906 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2907 }
2908 Self::StaleExpectedSchemaVersion => {
2909 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2910 }
2911 Self::InvalidExpectedSchemaVersion => {
2912 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2913 }
2914 Self::InvalidNextSchemaVersion => {
2915 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2916 }
2917 Self::AcceptedSchemaChangeWithoutVersionBump => {
2918 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2919 }
2920 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2921 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2922 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2923 Self::FingerprintMethodMismatch => {
2924 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2925 }
2926 Self::UnsupportedTransitionClass => {
2927 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2928 }
2929 Self::PhysicalRunnerMissing => {
2930 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2931 }
2932 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2933 Self::PublicationRaceLost => {
2934 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2935 }
2936 Self::InvalidAddColumnDefault => {
2937 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2938 }
2939 Self::InvalidAlterColumnDefault => {
2940 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2941 }
2942 Self::GeneratedIndexDropRejected => {
2943 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2944 }
2945 Self::SchemaRewriteRequiresMigration => {
2946 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2947 }
2948 Self::SchemaTransitionBudgetExceeded { .. } => {
2949 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2950 }
2951 Self::GeneratedFieldDefaultChangeRejected => {
2952 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2953 }
2954 Self::GeneratedFieldNullabilityChangeRejected => {
2955 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2956 }
2957 Self::RowLayoutVersionExhausted => {
2958 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2959 }
2960 }
2961 }
2962}
2963
2964#[repr(u8)]
2971#[derive(Clone, Copy, Eq, PartialEq)]
2972pub enum ErrorClass {
2973 Corruption,
2974 IncompatiblePersistedFormat,
2975 NotFound,
2976 Internal,
2977 Conflict,
2978 Unsupported,
2979 InvariantViolation,
2980}
2981
2982impl ErrorClass {
2983 #[must_use]
2985 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2986 match self {
2987 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2988 diagnostic_code::DiagnosticCode::StoreCorruption
2989 }
2990 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2991 Self::IncompatiblePersistedFormat => {
2992 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2993 }
2994 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2995 diagnostic_code::DiagnosticCode::StoreNotFound
2996 }
2997 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2998 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2999 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3000 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3001 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3002 }
3003 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3004 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3005 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3006 }
3007 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3008 }
3009 }
3010}
3011
3012impl fmt::Debug for ErrorClass {
3013 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3014 write!(f, "{}", *self as u8)
3015 }
3016}
3017
3018#[repr(u8)]
3025#[derive(Clone, Copy, Eq, PartialEq)]
3026pub enum ErrorOrigin {
3027 Serialize,
3028 Store,
3029 Index,
3030 Identity,
3031 Query,
3032 Planner,
3033 Cursor,
3034 Recovery,
3035 Response,
3036 Executor,
3037 Interface,
3038}
3039
3040impl ErrorOrigin {
3041 #[must_use]
3043 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3044 match self {
3045 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3046 Self::Store => diagnostic_code::ErrorOrigin::Store,
3047 Self::Index => diagnostic_code::ErrorOrigin::Index,
3048 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3049 Self::Query => diagnostic_code::ErrorOrigin::Query,
3050 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3051 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3052 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3053 Self::Response => diagnostic_code::ErrorOrigin::Response,
3054 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3055 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3056 }
3057 }
3058}
3059
3060impl fmt::Debug for ErrorOrigin {
3061 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3062 write!(f, "{}", *self as u8)
3063 }
3064}