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