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