apollo_federation/error/
mod.rs

1pub(crate) mod suggestion;
2
3use std::cmp::Ordering;
4use std::fmt::Display;
5use std::fmt::Formatter;
6use std::fmt::Write;
7use std::ops::Range;
8use std::sync::LazyLock;
9
10use apollo_compiler::InvalidNameError;
11use apollo_compiler::Name;
12use apollo_compiler::ast::OperationType;
13use apollo_compiler::parser::LineColumn;
14use apollo_compiler::validation::DiagnosticList;
15use apollo_compiler::validation::WithErrors;
16
17use crate::subgraph::SubgraphError;
18use crate::subgraph::spec::FederationSpecError;
19use crate::subgraph::typestate::HasMetadata;
20use crate::subgraph::typestate::Subgraph;
21
22/// Create an internal error.
23///
24/// # Example
25/// ```rust
26/// use apollo_federation::internal_error;
27/// use apollo_federation::error::FederationError;
28/// # fn may_be_none() -> Option<()> { None }
29///
30/// const NAME: &str = "the thing";
31/// let result: Result<(), FederationError> = may_be_none()
32///     .ok_or_else(|| internal_error!("Expected {NAME} to be Some"));
33/// ```
34#[macro_export]
35macro_rules! internal_error {
36    ( $( $arg:tt )+ ) => {
37        $crate::error::FederationError::internal(format!( $( $arg )+ ))
38    }
39}
40
41/// Break out of the current function, returning an internal error.
42///
43/// # Example
44/// ```rust
45/// use apollo_federation::bail;
46/// use apollo_federation::error::FederationError;
47/// # fn may_be_none() -> Option<()> { None }
48///
49/// fn example() -> Result<(), FederationError> {
50///     bail!("Something went horribly wrong");
51///     unreachable!()
52/// }
53/// #
54/// # _ = example();
55/// ```
56#[macro_export]
57macro_rules! bail {
58    ( $( $arg:tt )+ ) => {
59        return Err($crate::internal_error!( $( $arg )+ ).into())
60    }
61}
62
63/// A safe assertion: in debug mode, it panicks on failure, and in production, it returns an
64/// internal error.
65///
66/// Treat this as an assertion. It must only be used for conditions that *should never happen*
67/// in normal operation.
68///
69/// # Example
70/// ```rust,no_run
71/// use apollo_federation::ensure;
72/// use apollo_federation::error::FederationError;
73/// # fn may_be_none() -> Option<()> { None }
74///
75/// fn example() -> Result<(), FederationError> {
76///     ensure!(1 == 0, "Something went horribly wrong");
77///     unreachable!()
78/// }
79/// ```
80#[macro_export]
81macro_rules! ensure {
82    ( $expr:expr, $( $arg:tt )+ ) => {
83        #[cfg(debug_assertions)]
84        {
85            if false {
86                return Err($crate::error::FederationError::internal("ensure!() must be used in a function that returns a Result").into());
87            }
88            assert!($expr, $( $arg )+);
89        }
90
91        #[cfg(not(debug_assertions))]
92        if !$expr {
93            $crate::bail!( $( $arg )+ );
94        }
95    }
96}
97
98// What we really needed here was the string representations in enum form, this isn't meant to
99// replace AST components.
100#[derive(Clone, Debug, strum_macros::Display)]
101enum SchemaRootKind {
102    #[strum(to_string = "query")]
103    Query,
104    #[strum(to_string = "mutation")]
105    Mutation,
106    #[strum(to_string = "subscription")]
107    Subscription,
108}
109
110impl From<SchemaRootKind> for String {
111    fn from(value: SchemaRootKind) -> Self {
112        value.to_string()
113    }
114}
115
116#[derive(Clone, Debug, strum_macros::Display, PartialEq, Eq)]
117pub enum UnsupportedFeatureKind {
118    #[strum(to_string = "alias")]
119    Alias,
120}
121
122/// Modeled after `SubgraphLocation` defined in `apollo_composition`, so this struct can be
123/// converted to it.
124#[derive(Clone, Debug)]
125pub struct SubgraphLocation {
126    /// Subgraph name
127    pub subgraph: String, // TODO: Change this to `Arc<str>`, once `Merger` is updated.
128    /// Source code range in the subgraph schema document
129    pub range: Range<LineColumn>,
130}
131
132pub type Locations = Vec<SubgraphLocation>;
133
134pub(crate) trait HasLocations {
135    fn locations<T: HasMetadata>(&self, subgraph: &Subgraph<T>) -> Locations;
136}
137
138#[derive(Debug, Clone, thiserror::Error)]
139pub enum CompositionError {
140    #[error("[{subgraph}] {error}")]
141    SubgraphError {
142        subgraph: String,
143        error: SingleFederationError,
144        locations: Locations,
145    },
146    #[error("{message}")]
147    ContextualArgumentNotContextualInAllSubgraphs {
148        message: String,
149        locations: Locations,
150    },
151    #[error("{message}")]
152    EmptyMergedEnumType {
153        message: String,
154        locations: Locations,
155    },
156    #[error("{message}")]
157    EnumValueMismatch { message: String },
158    #[error("{message}")]
159    ExternalArgumentTypeMismatch { message: String },
160    #[error("{message}")]
161    ExternalTypeMismatch { message: String },
162    #[error("{message}")]
163    ExternalArgumentDefaultMismatch { message: String },
164    #[error("{message}")]
165    InvalidGraphQL { message: String },
166    #[error(transparent)]
167    InvalidGraphQLName(InvalidNameError),
168    #[error(r#"{message} in @fromContext substring "{context}""#)]
169    FromContextParseError { context: String, message: String },
170    #[error(
171        "Unsupported custom directive @{name} on fragment spread. Due to query transformations during planning, the router requires directives on fragment spreads to support both the FRAGMENT_SPREAD and INLINE_FRAGMENT locations."
172    )]
173    UnsupportedSpreadDirective { name: Name },
174    #[error("{message}")]
175    DirectiveDefinitionInvalid { message: String },
176    #[error("{message}")]
177    TypeDefinitionInvalid { message: String },
178    #[error("{message}")]
179    InterfaceObjectUsageError { message: String },
180    #[error("{message}")]
181    InterfaceKeyMissingImplementationType { message: String },
182    #[error("{message}")]
183    TypeKindMismatch { message: String },
184    #[error("{message}")]
185    ShareableHasMismatchedRuntimeTypes { message: String },
186    #[error("{message}")]
187    SatisfiabilityError { message: String },
188    #[error("{message}")]
189    MaxValidationSubgraphPathsExceeded { message: String },
190    #[error("{message}")]
191    InternalError { message: String },
192    #[error("{message}")]
193    ExternalArgumentMissing { message: String },
194    #[error("{message}")]
195    ExternalMissingOnBase { message: String },
196    #[error("{message}")]
197    MergedDirectiveApplicationOnExternal { message: String },
198    #[error("{message}")]
199    LinkImportNameMismatch { message: String },
200    #[error("{message}")]
201    InvalidFieldSharing {
202        message: String,
203        locations: Locations,
204    },
205    #[error(
206        "[{subgraph}] Type \"{dest}\" is an extension type, but there is no type definition for \"{dest}\" in any subgraph."
207    )]
208    ExtensionWithNoBase {
209        subgraph: String,
210        dest: String,
211        locations: Locations,
212    },
213    #[error("{message}")]
214    DirectiveCompositionError { message: String },
215    #[error("{message}")]
216    InconsistentInputObjectField { message: String },
217    #[error("{message}")]
218    RequiredArgumentMissingInSomeSubgraph {
219        message: String,
220        locations: Locations,
221    },
222    #[error("{message}")]
223    RequiredInputFieldMissingInSomeSubgraph {
224        message: String,
225        locations: Locations,
226    },
227    #[error("{message}")]
228    EmptyMergedInputType {
229        message: String,
230        locations: Locations,
231    },
232    #[error("{message}")]
233    InputFieldMergeFailed {
234        message: String,
235        locations: Locations,
236    },
237    #[error("{message}")]
238    FieldArgumentTypeMismatch { message: String },
239    #[error("{message}")]
240    FieldTypeMismatch { message: String },
241    #[error("{message}")]
242    OverrideCollisionWithAnotherDirective { message: String },
243    #[error("{message}")]
244    OverrideFromSelfError { message: String },
245    #[error("{message}")]
246    OverrideLabelInvalid { message: String },
247    #[error("{message}")]
248    OverrideOnInterface { message: String },
249    #[error("{message}")]
250    OverrideSourceHasOverride { message: String },
251    #[error("{message}")]
252    QueryRootMissing { message: String },
253    #[error("{message}")]
254    ArgumentDefaultMismatch {
255        message: String,
256        locations: Locations,
257    },
258    #[error("{message}")]
259    InputFieldDefaultMismatch {
260        message: String,
261        locations: Locations,
262    },
263}
264
265impl CompositionError {
266    pub fn code(&self) -> ErrorCode {
267        match self {
268            Self::SubgraphError { error, .. } => error.code(),
269            Self::ContextualArgumentNotContextualInAllSubgraphs { .. } => {
270                ErrorCode::ContextualArgumentNotContextualInAllSubgraphs
271            }
272            Self::EmptyMergedEnumType { .. } => ErrorCode::EmptyMergedEnumType,
273            Self::EnumValueMismatch { .. } => ErrorCode::EnumValueMismatch,
274            Self::ExternalTypeMismatch { .. } => ErrorCode::ExternalTypeMismatch,
275            Self::ExternalArgumentTypeMismatch { .. } => ErrorCode::ExternalArgumentTypeMismatch,
276            Self::ExternalArgumentDefaultMismatch { .. } => {
277                ErrorCode::ExternalArgumentDefaultMismatch
278            }
279            Self::InvalidGraphQL { .. } => ErrorCode::InvalidGraphQL,
280            Self::InvalidGraphQLName(..) => ErrorCode::InvalidGraphQL,
281            Self::FromContextParseError { .. } => ErrorCode::InvalidGraphQL,
282            Self::UnsupportedSpreadDirective { .. } => ErrorCode::InvalidGraphQL,
283            Self::DirectiveDefinitionInvalid { .. } => ErrorCode::DirectiveDefinitionInvalid,
284            Self::TypeDefinitionInvalid { .. } => ErrorCode::TypeDefinitionInvalid,
285            Self::InterfaceObjectUsageError { .. } => ErrorCode::InterfaceObjectUsageError,
286            Self::InterfaceKeyMissingImplementationType { .. } => {
287                ErrorCode::InterfaceKeyMissingImplementationType
288            }
289            Self::TypeKindMismatch { .. } => ErrorCode::TypeKindMismatch,
290            Self::ShareableHasMismatchedRuntimeTypes { .. } => {
291                ErrorCode::ShareableHasMismatchedRuntimeTypes
292            }
293            Self::SatisfiabilityError { .. } => ErrorCode::SatisfiabilityError,
294            Self::MaxValidationSubgraphPathsExceeded { .. } => {
295                ErrorCode::MaxValidationSubgraphPathsExceeded
296            }
297            Self::InternalError { .. } => ErrorCode::Internal,
298            Self::ExternalArgumentMissing { .. } => ErrorCode::ExternalArgumentMissing,
299            Self::ExternalMissingOnBase { .. } => ErrorCode::ExternalMissingOnBase,
300            Self::MergedDirectiveApplicationOnExternal { .. } => {
301                ErrorCode::MergedDirectiveApplicationOnExternal
302            }
303            Self::LinkImportNameMismatch { .. } => ErrorCode::LinkImportNameMismatch,
304            Self::InvalidFieldSharing { .. } => ErrorCode::InvalidFieldSharing,
305            Self::InconsistentInputObjectField { .. } => ErrorCode::Internal, // This is for hints, not errors
306            Self::RequiredArgumentMissingInSomeSubgraph { .. } => {
307                ErrorCode::RequiredArgumentMissingInSomeSubgraph
308            }
309            Self::RequiredInputFieldMissingInSomeSubgraph { .. } => {
310                ErrorCode::RequiredInputFieldMissingInSomeSubgraph
311            }
312            Self::EmptyMergedInputType { .. } => ErrorCode::EmptyMergedInputType,
313            Self::InputFieldMergeFailed { .. } => ErrorCode::InputFieldMergeFailed,
314            Self::ExtensionWithNoBase { .. } => ErrorCode::ExtensionWithNoBase,
315            Self::DirectiveCompositionError { .. } => ErrorCode::DirectiveCompositionError,
316            Self::FieldArgumentTypeMismatch { .. } => ErrorCode::FieldArgumentTypeMismatch,
317            Self::FieldTypeMismatch { .. } => ErrorCode::FieldTypeMismatch,
318            Self::OverrideCollisionWithAnotherDirective { .. } => {
319                ErrorCode::OverrideCollisionWithAnotherDirective
320            }
321            Self::OverrideFromSelfError { .. } => ErrorCode::OverrideFromSelfError,
322            Self::OverrideLabelInvalid { .. } => ErrorCode::OverrideLabelInvalid,
323            Self::OverrideOnInterface { .. } => ErrorCode::OverrideOnInterface,
324            Self::OverrideSourceHasOverride { .. } => ErrorCode::OverrideSourceHasOverride,
325            Self::QueryRootMissing { .. } => ErrorCode::QueryRootMissing,
326            Self::ArgumentDefaultMismatch { .. } => ErrorCode::FieldArgumentDefaultMismatch,
327            Self::InputFieldDefaultMismatch { .. } => ErrorCode::InputFieldDefaultMismatch,
328        }
329    }
330
331    pub(crate) fn append_message(self, appendix: impl Display) -> Self {
332        match self {
333            Self::EmptyMergedEnumType { message, locations } => Self::EmptyMergedEnumType {
334                message: format!("{message}{appendix}"),
335                locations,
336            },
337            Self::EnumValueMismatch { message } => Self::EnumValueMismatch {
338                message: format!("{message}{appendix}"),
339            },
340            Self::ExternalTypeMismatch { message } => Self::ExternalTypeMismatch {
341                message: format!("{message}{appendix}"),
342            },
343            Self::ExternalArgumentTypeMismatch { message } => Self::ExternalArgumentTypeMismatch {
344                message: format!("{message}{appendix}"),
345            },
346            Self::ExternalArgumentDefaultMismatch { message } => {
347                Self::ExternalArgumentDefaultMismatch {
348                    message: format!("{message}{appendix}"),
349                }
350            }
351            Self::InvalidGraphQL { message } => Self::InvalidGraphQL {
352                message: format!("{message}{appendix}"),
353            },
354            Self::DirectiveDefinitionInvalid { message } => Self::DirectiveDefinitionInvalid {
355                message: format!("{message}{appendix}"),
356            },
357            Self::TypeDefinitionInvalid { message } => Self::TypeDefinitionInvalid {
358                message: format!("{message}{appendix}"),
359            },
360            Self::InterfaceObjectUsageError { message } => Self::InterfaceObjectUsageError {
361                message: format!("{message}{appendix}"),
362            },
363            Self::InterfaceKeyMissingImplementationType { message } => {
364                Self::InterfaceKeyMissingImplementationType {
365                    message: format!("{message}{appendix}"),
366                }
367            }
368            Self::TypeKindMismatch { message } => Self::TypeKindMismatch {
369                message: format!("{message}{appendix}"),
370            },
371            Self::ShareableHasMismatchedRuntimeTypes { message } => {
372                Self::ShareableHasMismatchedRuntimeTypes {
373                    message: format!("{message}{appendix}"),
374                }
375            }
376            Self::SatisfiabilityError { message } => Self::SatisfiabilityError {
377                message: format!("{message}{appendix}"),
378            },
379            Self::MaxValidationSubgraphPathsExceeded { message } => {
380                Self::MaxValidationSubgraphPathsExceeded {
381                    message: format!("{message}{appendix}"),
382                }
383            }
384            Self::InternalError { message } => Self::InternalError {
385                message: format!("{message}{appendix}"),
386            },
387            Self::ExternalArgumentMissing { message } => Self::ExternalArgumentMissing {
388                message: format!("{message}{appendix}"),
389            },
390            Self::ExternalMissingOnBase { message } => Self::ExternalMissingOnBase {
391                message: format!("{message}{appendix}"),
392            },
393            Self::MergedDirectiveApplicationOnExternal { message } => {
394                Self::MergedDirectiveApplicationOnExternal {
395                    message: format!("{message}{appendix}"),
396                }
397            }
398            Self::LinkImportNameMismatch { message } => Self::LinkImportNameMismatch {
399                message: format!("{message}{appendix}"),
400            },
401            Self::InvalidFieldSharing { message, locations } => Self::InvalidFieldSharing {
402                message: format!("{message}{appendix}"),
403                locations,
404            },
405            Self::DirectiveCompositionError { message } => Self::DirectiveCompositionError {
406                message: format!("{message}{appendix}"),
407            },
408            Self::InconsistentInputObjectField { message } => Self::InconsistentInputObjectField {
409                message: format!("{message}{appendix}"),
410            },
411            Self::RequiredArgumentMissingInSomeSubgraph { message, locations } => {
412                Self::RequiredArgumentMissingInSomeSubgraph {
413                    message: format!("{message}{appendix}"),
414                    locations,
415                }
416            }
417            Self::RequiredInputFieldMissingInSomeSubgraph { message, locations } => {
418                Self::RequiredInputFieldMissingInSomeSubgraph {
419                    message: format!("{message}{appendix}"),
420                    locations,
421                }
422            }
423            Self::EmptyMergedInputType { message, locations } => Self::EmptyMergedInputType {
424                message: format!("{message}{appendix}"),
425                locations,
426            },
427            Self::InputFieldMergeFailed { message, locations } => Self::InputFieldMergeFailed {
428                message: format!("{message}{appendix}"),
429                locations,
430            },
431            Self::FieldArgumentTypeMismatch { message } => Self::FieldArgumentTypeMismatch {
432                message: format!("{message}{appendix}"),
433            },
434            Self::FieldTypeMismatch { message } => Self::FieldTypeMismatch {
435                message: format!("{message}{appendix}"),
436            },
437            Self::ContextualArgumentNotContextualInAllSubgraphs { message, locations } => {
438                Self::ContextualArgumentNotContextualInAllSubgraphs {
439                    message: format!("{message}{appendix}"),
440                    locations,
441                }
442            }
443            Self::ArgumentDefaultMismatch { message, locations } => Self::ArgumentDefaultMismatch {
444                message: format!("{message}{appendix}"),
445                locations,
446            },
447            Self::InputFieldDefaultMismatch { message, locations } => {
448                Self::InputFieldDefaultMismatch {
449                    message: format!("{message}{appendix}"),
450                    locations,
451                }
452            }
453            // Remaining errors do not have an obvious way to appending a message, so we just return self.
454            Self::SubgraphError { .. }
455            | Self::InvalidGraphQLName(..)
456            | Self::FromContextParseError { .. }
457            | Self::UnsupportedSpreadDirective { .. }
458            | Self::ExtensionWithNoBase { .. }
459            | Self::OverrideCollisionWithAnotherDirective { .. }
460            | Self::OverrideFromSelfError { .. }
461            | Self::OverrideLabelInvalid { .. }
462            | Self::OverrideOnInterface { .. }
463            | Self::OverrideSourceHasOverride { .. }
464            | Self::QueryRootMissing { .. } => self,
465        }
466    }
467
468    pub fn locations(&self) -> &[SubgraphLocation] {
469        match self {
470            Self::SubgraphError { locations, .. }
471            | Self::EmptyMergedEnumType { locations, .. }
472            | Self::InputFieldMergeFailed { locations, .. }
473            | Self::ExtensionWithNoBase { locations, .. }
474            | Self::RequiredArgumentMissingInSomeSubgraph { locations, .. }
475            | Self::RequiredInputFieldMissingInSomeSubgraph { locations, .. }
476            | Self::EmptyMergedInputType { locations, .. }
477            | Self::InvalidFieldSharing { locations, .. }
478            | Self::ArgumentDefaultMismatch { locations, .. }
479            | Self::InputFieldDefaultMismatch { locations, .. } => locations,
480            _ => &[],
481        }
482    }
483}
484
485impl SubgraphError {
486    pub fn to_composition_errors(&self) -> impl Iterator<Item = CompositionError> {
487        self.errors
488            .iter()
489            .map(move |error| CompositionError::SubgraphError {
490                subgraph: self.subgraph.clone(),
491                error: error.error.clone(),
492                locations: error
493                    .locations
494                    .iter()
495                    .map(|range| SubgraphLocation {
496                        subgraph: self.subgraph.clone(),
497                        range: range.clone(),
498                    })
499                    .collect(),
500            })
501    }
502}
503
504/* TODO(@tylerbloom): This is currently not needed. SingleFederation errors are aggregated using
505 * MultipleFederationErrors. This is then turned into a FederationError, then in a SubgraphError,
506 * and finally into a CompositionError. Not implementing this yet also ensures that any
507 * SingleFederationErrors that are intented on becoming SubgraphErrors still do.
508impl<E: Into<FederationError>> From<E> for SingleCompositionError {
509    fn from(_value: E) -> Self {
510        todo!()
511    }
512}
513*/
514
515#[derive(Debug, Clone, thiserror::Error)]
516pub enum SingleFederationError {
517    #[error(
518        "An internal error has occurred, please report this bug to Apollo.\n\nDetails: {message}"
519    )]
520    Internal { message: String },
521    #[error("An internal error has occurred, please report this bug to Apollo. Details: {0}")]
522    #[allow(private_interfaces)] // users should not inspect this.
523    InternalRebaseError(#[from] crate::operation::RebaseError),
524    // This is a known bug that will take time to fix, and does not require reporting.
525    #[error("{message}")]
526    InternalUnmergeableFields { message: String },
527    // InvalidGraphQL: We need to be able to modify the message text from apollo-compiler. So, we
528    //                 format the DiagnosticData into String here. We can add additional data as
529    //                 necessary.
530    #[error("{message}")]
531    InvalidGraphQL { message: String },
532    #[error(transparent)]
533    InvalidGraphQLName(#[from] InvalidNameError),
534    #[error("Subgraph invalid: {message}")]
535    InvalidSubgraph { message: String },
536    #[error("Operation name not found")]
537    UnknownOperation,
538    #[error("Must provide operation name if query contains multiple operations")]
539    OperationNameNotProvided,
540    #[error(r#"{message} in @fromContext substring "{context}""#)]
541    FromContextParseError { context: String, message: String },
542    #[error(
543        "Unsupported custom directive @{name} on fragment spread. Due to query transformations during planning, the router requires directives on fragment spreads to support both the FRAGMENT_SPREAD and INLINE_FRAGMENT locations."
544    )]
545    UnsupportedSpreadDirective { name: Name },
546    #[error("{message}")]
547    DirectiveDefinitionInvalid { message: String },
548    #[error("{message}")]
549    TypeDefinitionInvalid { message: String },
550    #[error("{message}")]
551    UnsupportedFederationDirective { message: String },
552    #[error("{message}")]
553    UnsupportedFederationVersion { message: String },
554    #[error("{message}")]
555    UnsupportedLinkedFeature { message: String },
556    #[error("{message}")]
557    UnknownFederationLinkVersion { message: String },
558    #[error("{message}")]
559    UnknownLinkVersion { message: String },
560    #[error(
561        "On type \"{target_type}\", for {application}: field {inner_coordinate} cannot be included because it has arguments (fields with argument are not allowed in @key)"
562    )]
563    KeyFieldsHasArgs {
564        target_type: Name,
565        application: String,
566        inner_coordinate: String,
567    },
568    #[error(
569        "On field \"{coordinate}\", for {application}: field {inner_coordinate} cannot be included because it has arguments (fields with argument are not allowed in @provides)"
570    )]
571    ProvidesFieldsHasArgs {
572        coordinate: String,
573        application: String,
574        inner_coordinate: String,
575    },
576    #[error("On field \"{coordinate}\", for {application}: {message}")]
577    ProvidesFieldsMissingExternal {
578        coordinate: String,
579        application: String,
580        message: String,
581    },
582    #[error("On field \"{coordinate}\", for {application}: {message}")]
583    RequiresFieldsMissingExternal {
584        coordinate: String,
585        application: String,
586        message: String,
587    },
588    #[error("{message}")]
589    KeyUnsupportedOnInterface { message: String },
590    #[error("{message}")]
591    ProvidesUnsupportedOnInterface { message: String },
592    #[error("{message}")]
593    RequiresUnsupportedOnInterface { message: String },
594    #[error(
595        "On type \"{target_type}\", for {application}: cannot have directive applications in the @key(fields:) argument but found {applied_directives}."
596    )]
597    KeyHasDirectiveInFieldsArg {
598        target_type: Name,
599        application: String,
600        applied_directives: String,
601    },
602    #[error(
603        "On field \"{coordinate}\", for {application}: cannot have directive applications in the @provides(fields:) argument but found {applied_directives}."
604    )]
605    ProvidesHasDirectiveInFieldsArg {
606        coordinate: String,
607        application: String,
608        applied_directives: String,
609    },
610    #[error(
611        "On field \"{coordinate}\", for {application}: cannot have directive applications in the @requires(fields:) argument but found {applied_directives}."
612    )]
613    RequiresHasDirectiveInFieldsArg {
614        coordinate: String,
615        application: String,
616        applied_directives: String,
617    },
618    #[error("{message}")]
619    ExternalUnused { message: String },
620    #[error(
621        "Type {type_name} contains only external fields and all those fields are all unused (they do not appear in any @key, @provides or @requires)."
622    )]
623    TypeWithOnlyUnusedExternal { type_name: Name },
624    #[error("{message}")]
625    ProvidesOnNonObjectField { message: String },
626    #[error(
627        "On type \"{target_type}\", for {application}: Invalid value for argument \"fields\": must be a string."
628    )]
629    KeyInvalidFieldsType {
630        target_type: Name,
631        application: String,
632    },
633    #[error(
634        "On field \"{coordinate}\", for {application}: Invalid value for argument \"fields\": must be a string."
635    )]
636    ProvidesInvalidFieldsType {
637        coordinate: String,
638        application: String,
639    },
640    #[error(
641        "On field \"{coordinate}\", for {application}: Invalid value for argument \"fields\": must be a string."
642    )]
643    RequiresInvalidFieldsType {
644        coordinate: String,
645        application: String,
646    },
647    #[error("On type \"{target_type}\", for {application}: {message}")]
648    KeyInvalidFields {
649        target_type: Name,
650        application: String,
651        message: String,
652    },
653    #[error("On field \"{coordinate}\", for {application}: {message}")]
654    ProvidesInvalidFields {
655        coordinate: String,
656        application: String,
657        message: String,
658    },
659    #[error("On field \"{coordinate}\", for {application}: {message}")]
660    RequiresInvalidFields {
661        coordinate: String,
662        application: String,
663        message: String,
664    },
665    #[error("On type \"{target_type}\", for {application}: {message}")]
666    KeyFieldsSelectInvalidType {
667        target_type: Name,
668        application: String,
669        message: String,
670    },
671    #[error(
672        "The schema has a type named \"{expected_name}\" but it is not set as the query root type (\"{found_name}\" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name."
673    )]
674    RootQueryUsed {
675        expected_name: Name,
676        found_name: Name,
677    },
678    #[error(
679        "The schema has a type named \"{expected_name}\" but it is not set as the mutation root type (\"{found_name}\" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name."
680    )]
681    RootMutationUsed {
682        expected_name: Name,
683        found_name: Name,
684    },
685    #[error(
686        "The schema has a type named \"{expected_name}\" but it is not set as the subscription root type (\"{found_name}\" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name."
687    )]
688    RootSubscriptionUsed {
689        expected_name: Name,
690        found_name: Name,
691    },
692    #[error("{message}")]
693    InvalidSubgraphName { message: String },
694    #[error("{message}")]
695    NoQueries { message: String },
696    #[error("{message}")]
697    InterfaceFieldNoImplem { message: String },
698    #[error("{message}")]
699    ExternalTypeMismatch { message: String },
700    #[error("{message}")]
701    ExternalCollisionWithAnotherDirective { message: String },
702    #[error("{message}")]
703    ExternalArgumentMissing { message: String },
704    #[error("{message}")]
705    ExternalArgumentTypeMismatch { message: String },
706    #[error("{message}")]
707    ExternalArgumentDefaultMismatch { message: String },
708    #[error("{message}")]
709    ExternalOnInterface { message: String },
710    #[error("{message}")]
711    MergedDirectiveApplicationOnExternal { message: String },
712    #[error("{message}")]
713    FieldTypeMismatch { message: String },
714    #[error("{message}")]
715    FieldArgumentTypeMismatch { message: String },
716    #[error("{message}")]
717    InputFieldDefaultMismatch { message: String },
718    #[error("{message}")]
719    FieldArgumentDefaultMismatch { message: String },
720    #[error("{message}")]
721    ExtensionWithNoBase { message: String },
722    #[error("{message}")]
723    ExternalMissingOnBase { message: String },
724    #[error("{message}")]
725    InvalidFieldSharing { message: String },
726    #[error("{message}")]
727    InvalidShareableUsage { message: String },
728    #[error("{message}")]
729    InvalidLinkDirectiveUsage { message: String },
730    #[error("{message}")]
731    InvalidLinkIdentifier { message: String },
732    #[error("{message}")]
733    ReferencedInaccessible { message: String },
734    #[error("{message}")]
735    DefaultValueUsesInaccessible { message: String },
736    #[error("{message}")]
737    QueryRootTypeInaccessible { message: String },
738    #[error("{message}")]
739    RequiredInaccessible { message: String },
740    #[error("{message}")]
741    ImplementedByInaccessible { message: String },
742    #[error("{message}")]
743    DisallowedInaccessible { message: String },
744    #[error("{message}")]
745    OnlyInaccessibleChildren { message: String },
746    #[error("{message}")]
747    RequiredInputFieldMissingInSomeSubgraph { message: String },
748    #[error("{message}")]
749    RequiredArgumentMissingInSomeSubgraph { message: String },
750    #[error("{message}")]
751    EmptyMergedInputType { message: String },
752    #[error("{message}")]
753    EnumValueMismatch { message: String },
754    #[error("{message}")]
755    EmptyMergedEnumType { message: String },
756    #[error("{message}")]
757    ShareableHasMismatchedRuntimeTypes { message: String },
758    #[error("{message}")]
759    SatisfiabilityError { message: String },
760    #[error("{message}")]
761    OverrideFromSelfError { message: String },
762    #[error("{message}")]
763    OverrideSourceHasOverride { message: String },
764    #[error("{message}")]
765    OverrideCollisionWithAnotherDirective { message: String },
766    #[error("{message}")]
767    OverrideOnInterface { message: String },
768    #[error("{message}")]
769    UnsupportedFeature {
770        message: String,
771        kind: UnsupportedFeatureKind,
772    },
773    #[error("{message}")]
774    InvalidFederationSupergraph { message: String },
775    #[error("{message}")]
776    DownstreamServiceError { message: String },
777    #[error("{message}")]
778    DirectiveCompositionError { message: String },
779    #[error("{message}")]
780    InterfaceObjectUsageError { message: String },
781    #[error("{message}")]
782    InterfaceKeyNotOnImplementation { message: String },
783    #[error("{message}")]
784    InterfaceKeyMissingImplementationType { message: String },
785    #[error("@defer is not supported on subscriptions")]
786    DeferredSubscriptionUnsupported,
787    #[error("{message}")]
788    QueryPlanComplexityExceeded { message: String },
789    #[error("the caller requested cancellation")]
790    PlanningCancelled,
791    #[error("No plan was found when subgraphs were disabled")]
792    NoPlanFoundWithDisabledSubgraphs,
793    #[error("Context name \"{name}\" may not contain an underscore.")]
794    ContextNameContainsUnderscore { name: String },
795    #[error("Context name \"{name}\" is invalid. It should have only alphanumeric characters.")]
796    ContextNameInvalid { name: String },
797    #[error("{message}")]
798    ContextNotSet { message: String },
799    #[error("{message}")]
800    NoContextReferenced { message: String },
801    #[error("{message}")]
802    NoSelectionForContext { message: String },
803    #[error("{message}")]
804    ContextNoResolvableKey { message: String },
805    #[error("@cost cannot be applied to interface \"{interface}.{field}\"")]
806    CostAppliedToInterfaceField { interface: Name, field: Name },
807    #[error("{message}")]
808    ContextSelectionInvalid { message: String },
809    #[error("{message}")]
810    ListSizeAppliedToNonList { message: String },
811    #[error("{message}")]
812    ListSizeInvalidAssumedSize { message: String },
813    #[error("{message}")]
814    ListSizeInvalidSlicingArgument { message: String },
815    #[error("{message}")]
816    ListSizeInvalidSizedField { message: String },
817    #[error("{message}")]
818    InvalidTagName { message: String },
819    #[error("{message}")]
820    QueryRootMissing { message: String },
821}
822
823impl SingleFederationError {
824    pub fn code(&self) -> ErrorCode {
825        match self {
826            SingleFederationError::Internal { .. } => ErrorCode::Internal,
827            SingleFederationError::InternalRebaseError { .. } => ErrorCode::Internal,
828            SingleFederationError::InternalUnmergeableFields { .. } => ErrorCode::Internal,
829            SingleFederationError::InvalidGraphQL { .. }
830            | SingleFederationError::InvalidGraphQLName(_) => ErrorCode::InvalidGraphQL,
831            SingleFederationError::InvalidSubgraph { .. } => ErrorCode::InvalidGraphQL,
832            // Technically it's not invalid graphql, but it is invalid syntax inside graphql...
833            SingleFederationError::FromContextParseError { .. } => ErrorCode::InvalidGraphQL,
834            // TODO(@goto-bus-stop): this should have a different error code: it's not invalid,
835            // just unsupported due to internal limitations.
836            SingleFederationError::UnsupportedSpreadDirective { .. } => ErrorCode::InvalidGraphQL,
837            // TODO(@goto-bus-stop): this should have a different error code: it's not the graphql
838            // that's invalid, but the operation name
839            SingleFederationError::UnknownOperation => ErrorCode::InvalidGraphQL,
840            SingleFederationError::OperationNameNotProvided => ErrorCode::InvalidGraphQL,
841            SingleFederationError::DirectiveDefinitionInvalid { .. } => {
842                ErrorCode::DirectiveDefinitionInvalid
843            }
844            SingleFederationError::TypeDefinitionInvalid { .. } => ErrorCode::TypeDefinitionInvalid,
845            SingleFederationError::UnsupportedFederationDirective { .. } => {
846                ErrorCode::UnsupportedFederationDirective
847            }
848            SingleFederationError::UnsupportedFederationVersion { .. } => {
849                ErrorCode::UnsupportedFederationVersion
850            }
851            SingleFederationError::UnsupportedLinkedFeature { .. } => {
852                ErrorCode::UnsupportedLinkedFeature
853            }
854            SingleFederationError::UnknownFederationLinkVersion { .. } => {
855                ErrorCode::UnknownFederationLinkVersion
856            }
857            SingleFederationError::UnknownLinkVersion { .. } => ErrorCode::UnknownLinkVersion,
858            SingleFederationError::KeyFieldsHasArgs { .. } => ErrorCode::KeyFieldsHasArgs,
859            SingleFederationError::ProvidesFieldsHasArgs { .. } => ErrorCode::ProvidesFieldsHasArgs,
860            SingleFederationError::ProvidesFieldsMissingExternal { .. } => {
861                ErrorCode::ProvidesFieldsMissingExternal
862            }
863            SingleFederationError::RequiresFieldsMissingExternal { .. } => {
864                ErrorCode::RequiresFieldsMissingExternal
865            }
866            SingleFederationError::KeyUnsupportedOnInterface { .. } => {
867                ErrorCode::KeyUnsupportedOnInterface
868            }
869            SingleFederationError::ProvidesUnsupportedOnInterface { .. } => {
870                ErrorCode::ProvidesUnsupportedOnInterface
871            }
872            SingleFederationError::RequiresUnsupportedOnInterface { .. } => {
873                ErrorCode::RequiresUnsupportedOnInterface
874            }
875            SingleFederationError::KeyHasDirectiveInFieldsArg { .. } => {
876                ErrorCode::KeyDirectiveInFieldsArgs
877            }
878            SingleFederationError::ProvidesHasDirectiveInFieldsArg { .. } => {
879                ErrorCode::ProvidesDirectiveInFieldsArgs
880            }
881            SingleFederationError::RequiresHasDirectiveInFieldsArg { .. } => {
882                ErrorCode::RequiresDirectiveInFieldsArgs
883            }
884            SingleFederationError::ExternalUnused { .. } => ErrorCode::ExternalUnused,
885            SingleFederationError::TypeWithOnlyUnusedExternal { .. } => {
886                ErrorCode::TypeWithOnlyUnusedExternal
887            }
888            SingleFederationError::ProvidesOnNonObjectField { .. } => {
889                ErrorCode::ProvidesOnNonObjectField
890            }
891            SingleFederationError::KeyInvalidFieldsType { .. } => ErrorCode::KeyInvalidFieldsType,
892            SingleFederationError::ProvidesInvalidFieldsType { .. } => {
893                ErrorCode::ProvidesInvalidFieldsType
894            }
895            SingleFederationError::RequiresInvalidFieldsType { .. } => {
896                ErrorCode::RequiresInvalidFieldsType
897            }
898            SingleFederationError::KeyInvalidFields { .. } => ErrorCode::KeyInvalidFields,
899            SingleFederationError::ProvidesInvalidFields { .. } => ErrorCode::ProvidesInvalidFields,
900            SingleFederationError::RequiresInvalidFields { .. } => ErrorCode::RequiresInvalidFields,
901            SingleFederationError::KeyFieldsSelectInvalidType { .. } => {
902                ErrorCode::KeyFieldsSelectInvalidType
903            }
904            SingleFederationError::RootQueryUsed { .. } => ErrorCode::RootQueryUsed,
905            SingleFederationError::RootMutationUsed { .. } => ErrorCode::RootMutationUsed,
906            SingleFederationError::RootSubscriptionUsed { .. } => ErrorCode::RootSubscriptionUsed,
907            SingleFederationError::InvalidSubgraphName { .. } => ErrorCode::InvalidSubgraphName,
908            SingleFederationError::NoQueries { .. } => ErrorCode::NoQueries,
909            SingleFederationError::InterfaceFieldNoImplem { .. } => {
910                ErrorCode::InterfaceFieldNoImplem
911            }
912            SingleFederationError::ExternalTypeMismatch { .. } => ErrorCode::ExternalTypeMismatch,
913            SingleFederationError::ExternalCollisionWithAnotherDirective { .. } => {
914                ErrorCode::ExternalCollisionWithAnotherDirective
915            }
916            SingleFederationError::ExternalArgumentMissing { .. } => {
917                ErrorCode::ExternalArgumentMissing
918            }
919            SingleFederationError::ExternalArgumentTypeMismatch { .. } => {
920                ErrorCode::ExternalArgumentTypeMismatch
921            }
922            SingleFederationError::ExternalArgumentDefaultMismatch { .. } => {
923                ErrorCode::ExternalArgumentDefaultMismatch
924            }
925            SingleFederationError::ExternalOnInterface { .. } => ErrorCode::ExternalOnInterface,
926            SingleFederationError::MergedDirectiveApplicationOnExternal { .. } => {
927                ErrorCode::MergedDirectiveApplicationOnExternal
928            }
929            SingleFederationError::FieldTypeMismatch { .. } => ErrorCode::FieldTypeMismatch,
930            SingleFederationError::FieldArgumentTypeMismatch { .. } => {
931                ErrorCode::FieldArgumentTypeMismatch
932            }
933            SingleFederationError::InputFieldDefaultMismatch { .. } => {
934                ErrorCode::InputFieldDefaultMismatch
935            }
936            SingleFederationError::FieldArgumentDefaultMismatch { .. } => {
937                ErrorCode::FieldArgumentDefaultMismatch
938            }
939            SingleFederationError::ExtensionWithNoBase { .. } => ErrorCode::ExtensionWithNoBase,
940            SingleFederationError::ExternalMissingOnBase { .. } => ErrorCode::ExternalMissingOnBase,
941            SingleFederationError::InvalidFieldSharing { .. } => ErrorCode::InvalidFieldSharing,
942            SingleFederationError::InvalidShareableUsage { .. } => ErrorCode::InvalidShareableUsage,
943            SingleFederationError::InvalidLinkDirectiveUsage { .. } => {
944                ErrorCode::InvalidLinkDirectiveUsage
945            }
946            SingleFederationError::InvalidLinkIdentifier { .. } => ErrorCode::InvalidLinkIdentifier,
947            SingleFederationError::ReferencedInaccessible { .. } => {
948                ErrorCode::ReferencedInaccessible
949            }
950            SingleFederationError::DefaultValueUsesInaccessible { .. } => {
951                ErrorCode::DefaultValueUsesInaccessible
952            }
953            SingleFederationError::QueryRootTypeInaccessible { .. } => {
954                ErrorCode::QueryRootTypeInaccessible
955            }
956            SingleFederationError::RequiredInaccessible { .. } => ErrorCode::RequiredInaccessible,
957            SingleFederationError::ImplementedByInaccessible { .. } => {
958                ErrorCode::ImplementedByInaccessible
959            }
960            SingleFederationError::DisallowedInaccessible { .. } => {
961                ErrorCode::DisallowedInaccessible
962            }
963            SingleFederationError::OnlyInaccessibleChildren { .. } => {
964                ErrorCode::OnlyInaccessibleChildren
965            }
966            SingleFederationError::RequiredInputFieldMissingInSomeSubgraph { .. } => {
967                ErrorCode::RequiredInputFieldMissingInSomeSubgraph
968            }
969            SingleFederationError::RequiredArgumentMissingInSomeSubgraph { .. } => {
970                ErrorCode::RequiredArgumentMissingInSomeSubgraph
971            }
972            SingleFederationError::EmptyMergedInputType { .. } => ErrorCode::EmptyMergedInputType,
973            SingleFederationError::EnumValueMismatch { .. } => ErrorCode::EnumValueMismatch,
974            SingleFederationError::EmptyMergedEnumType { .. } => ErrorCode::EmptyMergedEnumType,
975            SingleFederationError::ShareableHasMismatchedRuntimeTypes { .. } => {
976                ErrorCode::ShareableHasMismatchedRuntimeTypes
977            }
978            SingleFederationError::SatisfiabilityError { .. } => ErrorCode::SatisfiabilityError,
979            SingleFederationError::OverrideFromSelfError { .. } => ErrorCode::OverrideFromSelfError,
980            SingleFederationError::OverrideSourceHasOverride { .. } => {
981                ErrorCode::OverrideSourceHasOverride
982            }
983            SingleFederationError::OverrideCollisionWithAnotherDirective { .. } => {
984                ErrorCode::OverrideCollisionWithAnotherDirective
985            }
986            SingleFederationError::OverrideOnInterface { .. } => ErrorCode::OverrideOnInterface,
987            SingleFederationError::UnsupportedFeature { .. } => ErrorCode::UnsupportedFeature,
988            SingleFederationError::InvalidFederationSupergraph { .. } => {
989                ErrorCode::InvalidFederationSupergraph
990            }
991            SingleFederationError::DownstreamServiceError { .. } => {
992                ErrorCode::DownstreamServiceError
993            }
994            SingleFederationError::DirectiveCompositionError { .. } => {
995                ErrorCode::DirectiveCompositionError
996            }
997            SingleFederationError::InterfaceObjectUsageError { .. } => {
998                ErrorCode::InterfaceObjectUsageError
999            }
1000            SingleFederationError::InterfaceKeyNotOnImplementation { .. } => {
1001                ErrorCode::InterfaceKeyNotOnImplementation
1002            }
1003            SingleFederationError::InterfaceKeyMissingImplementationType { .. } => {
1004                ErrorCode::InterfaceKeyMissingImplementationType
1005            }
1006            SingleFederationError::DeferredSubscriptionUnsupported => ErrorCode::Internal,
1007            SingleFederationError::QueryPlanComplexityExceeded { .. } => {
1008                ErrorCode::QueryPlanComplexityExceededError
1009            }
1010            SingleFederationError::PlanningCancelled => ErrorCode::Internal,
1011            SingleFederationError::NoPlanFoundWithDisabledSubgraphs => {
1012                ErrorCode::NoPlanFoundWithDisabledSubgraphs
1013            }
1014            SingleFederationError::ContextNameContainsUnderscore { .. } => {
1015                ErrorCode::ContextNameContainsUnderscore
1016            }
1017            SingleFederationError::ContextNameInvalid { .. } => ErrorCode::ContextNameInvalid,
1018            SingleFederationError::ContextNotSet { .. } => ErrorCode::ContextNotSet,
1019            SingleFederationError::NoContextReferenced { .. } => ErrorCode::NoContextReferenced,
1020            SingleFederationError::NoSelectionForContext { .. } => ErrorCode::NoSelectionForContext,
1021            SingleFederationError::ContextNoResolvableKey { .. } => {
1022                ErrorCode::ContextNoResolvableKey
1023            }
1024            SingleFederationError::ContextSelectionInvalid { .. } => {
1025                ErrorCode::ContextSelectionInvalid
1026            }
1027            SingleFederationError::CostAppliedToInterfaceField { .. } => {
1028                ErrorCode::CostAppliedToInterfaceField
1029            }
1030            SingleFederationError::ListSizeAppliedToNonList { .. } => {
1031                ErrorCode::ListSizeAppliedToNonList
1032            }
1033            SingleFederationError::ListSizeInvalidAssumedSize { .. } => {
1034                ErrorCode::ListSizeInvalidAssumedSize
1035            }
1036            SingleFederationError::ListSizeInvalidSlicingArgument { .. } => {
1037                ErrorCode::ListSizeInvalidSlicingArgument
1038            }
1039            SingleFederationError::ListSizeInvalidSizedField { .. } => {
1040                ErrorCode::ListSizeInvalidSizedField
1041            }
1042            #[allow(unused)]
1043            SingleFederationError::InvalidFieldSharing { .. } => ErrorCode::InvalidFieldSharing,
1044            SingleFederationError::InvalidTagName { .. } => ErrorCode::InvalidTagName,
1045            SingleFederationError::QueryRootMissing { .. } => ErrorCode::QueryRootMissing,
1046        }
1047    }
1048
1049    pub fn code_string(&self) -> String {
1050        self.code().definition().code().to_string()
1051    }
1052
1053    pub(crate) fn root_already_used(
1054        operation_type: OperationType,
1055        expected_name: Name,
1056        found_name: Name,
1057    ) -> Self {
1058        match operation_type {
1059            OperationType::Query => Self::RootQueryUsed {
1060                expected_name,
1061                found_name,
1062            },
1063            OperationType::Mutation => Self::RootMutationUsed {
1064                expected_name,
1065                found_name,
1066            },
1067            OperationType::Subscription => Self::RootSubscriptionUsed {
1068                expected_name,
1069                found_name,
1070            },
1071        }
1072    }
1073}
1074
1075impl From<InvalidNameError> for FederationError {
1076    fn from(err: InvalidNameError) -> Self {
1077        SingleFederationError::from(err).into()
1078    }
1079}
1080
1081impl From<FederationSpecError> for FederationError {
1082    fn from(err: FederationSpecError) -> Self {
1083        // TODO: When we get around to finishing the composition port, we should really switch it to
1084        // using FederationError instead of FederationSpecError.
1085        let message = err.to_string();
1086        match err {
1087            FederationSpecError::UnsupportedVersionError { .. } => {
1088                SingleFederationError::UnsupportedFederationVersion { message }.into()
1089            }
1090            FederationSpecError::UnsupportedFederationDirective { .. } => {
1091                SingleFederationError::UnsupportedFederationDirective { message }.into()
1092            }
1093            FederationSpecError::InvalidGraphQLName(message) => message.into(),
1094        }
1095    }
1096}
1097
1098#[derive(Debug, Clone, thiserror::Error, Default)]
1099pub struct MultipleFederationErrors {
1100    pub(crate) errors: Vec<SingleFederationError>,
1101}
1102
1103impl MultipleFederationErrors {
1104    pub fn new() -> Self {
1105        Self { errors: vec![] }
1106    }
1107
1108    pub fn push(&mut self, error: FederationError) {
1109        match error {
1110            FederationError::SingleFederationError(error) => {
1111                self.errors.push(error);
1112            }
1113            FederationError::MultipleFederationErrors(errors) => {
1114                self.errors.extend(errors.errors);
1115            }
1116            FederationError::AggregateFederationError(errors) => {
1117                self.errors.extend(errors.causes);
1118            }
1119        }
1120    }
1121
1122    pub(crate) fn and_try(mut self, other: Result<(), FederationError>) -> Self {
1123        match other {
1124            Ok(_) => self,
1125            Err(e) => {
1126                self.push(e);
1127                self
1128            }
1129        }
1130    }
1131}
1132
1133impl Display for MultipleFederationErrors {
1134    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1135        write!(f, "The following errors occurred:")?;
1136        for error in &self.errors {
1137            write!(f, "\n  - ")?;
1138            for c in error.to_string().chars() {
1139                if c == '\n' {
1140                    write!(f, "\n    ")?;
1141                } else {
1142                    f.write_char(c)?;
1143                }
1144            }
1145        }
1146        Ok(())
1147    }
1148}
1149
1150impl FromIterator<SingleFederationError> for MultipleFederationErrors {
1151    fn from_iter<T: IntoIterator<Item = SingleFederationError>>(iter: T) -> Self {
1152        Self {
1153            errors: iter.into_iter().collect(),
1154        }
1155    }
1156}
1157
1158#[derive(Debug, Clone, thiserror::Error)]
1159pub struct AggregateFederationError {
1160    pub code: String,
1161    pub message: String,
1162    pub causes: Vec<SingleFederationError>,
1163}
1164
1165impl Display for AggregateFederationError {
1166    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1167        write!(f, "[{}] {}\nCaused by:", self.code, self.message)?;
1168        for error in &self.causes {
1169            write!(f, "\n\n  - ")?;
1170            for c in error.to_string().chars() {
1171                if c == '\n' {
1172                    write!(f, "\n    ")?;
1173                } else {
1174                    f.write_char(c)?;
1175                }
1176            }
1177        }
1178        Ok(())
1179    }
1180}
1181
1182// PORT_NOTE: Often times, JS functions would either throw/return a GraphQLError, return a vector
1183// of GraphQLErrors, or take a vector of GraphQLErrors and group them together under an
1184// AggregateGraphQLError which itself would have a specific error message and code, and throw that.
1185// We represent all these cases with an enum, and delegate to the members.
1186#[derive(Clone, thiserror::Error)]
1187pub enum FederationError {
1188    #[error(transparent)]
1189    SingleFederationError(#[from] SingleFederationError),
1190    #[error(transparent)]
1191    MultipleFederationErrors(#[from] MultipleFederationErrors),
1192    #[error(transparent)]
1193    AggregateFederationError(#[from] AggregateFederationError),
1194}
1195
1196impl std::fmt::Debug for FederationError {
1197    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1198        match self {
1199            Self::SingleFederationError(inner) => std::fmt::Debug::fmt(inner, f),
1200            Self::MultipleFederationErrors(inner) => std::fmt::Debug::fmt(inner, f),
1201            Self::AggregateFederationError(inner) => std::fmt::Debug::fmt(inner, f),
1202        }
1203    }
1204}
1205
1206impl From<DiagnosticList> for FederationError {
1207    fn from(value: DiagnosticList) -> Self {
1208        let errors: Vec<_> = value
1209            .iter()
1210            .map(|d| SingleFederationError::InvalidGraphQL {
1211                message: d.to_string(),
1212            })
1213            .collect();
1214        match errors.len().cmp(&1) {
1215            Ordering::Less => internal_error!("diagnostic list is unexpectedly empty"),
1216            Ordering::Equal => errors[0].clone().into(),
1217            Ordering::Greater => MultipleFederationErrors { errors }.into(),
1218        }
1219    }
1220}
1221
1222impl<T> From<WithErrors<T>> for FederationError {
1223    fn from(value: WithErrors<T>) -> Self {
1224        value.errors.into()
1225    }
1226}
1227
1228// Used for when we condition on a type `T: TryInto<U>`, but we have an infallible conversion of
1229// `T: Into<U>`. This allows us to unwrap the `Result<U, Infallible>` with `?`.
1230impl From<std::convert::Infallible> for FederationError {
1231    fn from(_: std::convert::Infallible) -> Self {
1232        unreachable!("Infallible should never be converted to FederationError")
1233    }
1234}
1235
1236impl FederationError {
1237    pub fn internal(message: impl Into<String>) -> Self {
1238        SingleFederationError::Internal {
1239            message: message.into(),
1240        }
1241        .into()
1242    }
1243
1244    pub fn merge(self, other: Self) -> Self {
1245        let mut result = MultipleFederationErrors::new();
1246        result.push(self);
1247        result.push(other);
1248        result.into()
1249    }
1250
1251    pub fn into_errors(self) -> Vec<SingleFederationError> {
1252        match self {
1253            FederationError::SingleFederationError(e) => vec![e],
1254            FederationError::MultipleFederationErrors(e) => e.errors,
1255            FederationError::AggregateFederationError(e) => e.causes,
1256        }
1257    }
1258
1259    pub fn errors(&self) -> Vec<&SingleFederationError> {
1260        match self {
1261            FederationError::SingleFederationError(e) => vec![e],
1262            FederationError::MultipleFederationErrors(e) => e.errors.iter().collect(),
1263            FederationError::AggregateFederationError(e) => e.causes.iter().collect(),
1264        }
1265    }
1266
1267    pub fn has_invalid_graphql_error(&self) -> bool {
1268        self.errors()
1269            .into_iter()
1270            .any(|e| matches!(e, SingleFederationError::InvalidGraphQL { .. }))
1271    }
1272}
1273
1274// Similar to `multi_try` crate, but with `FederationError` instead of `Vec<E>`.
1275pub trait MultiTry<U> {
1276    type Output;
1277
1278    fn and_try(self, other: Result<U, FederationError>) -> Self::Output;
1279}
1280
1281impl<U> MultiTry<U> for Result<(), FederationError> {
1282    type Output = Result<U, FederationError>;
1283
1284    fn and_try(self, other: Result<U, FederationError>) -> Result<U, FederationError> {
1285        match (self, other) {
1286            (Ok(_a), Ok(b)) => Ok(b),
1287            (Ok(_a), Err(b)) => Err(b),
1288            (Err(a), Ok(_b)) => Err(a),
1289            (Err(a), Err(b)) => Err(a.merge(b)),
1290        }
1291    }
1292}
1293
1294pub trait MultiTryAll: Sized + Iterator {
1295    /// Apply `predicate` on all elements of the iterator, collecting all errors (if any).
1296    /// - Returns Ok(()), if all elements are Ok.
1297    /// - Otherwise, returns a FederationError with all errors.
1298    /// - Note: Not to be confused with `try_for_each`, which stops on the first error.
1299    fn try_for_all<F>(self, mut predicate: F) -> Result<(), FederationError>
1300    where
1301        F: FnMut(Self::Item) -> Result<(), FederationError>,
1302    {
1303        let mut errors = MultipleFederationErrors::new();
1304        for item in self {
1305            match predicate(item) {
1306                Ok(()) => {}
1307                Err(e) => errors.push(e),
1308            }
1309        }
1310        errors.into_result()
1311    }
1312}
1313
1314impl<I: Iterator> MultiTryAll for I {}
1315
1316impl MultipleFederationErrors {
1317    /// Converts into `Result<(), FederationError>`.
1318    /// - The return value can be either Ok, Err with a SingleFederationError or MultipleFederationErrors,
1319    ///   depending on the number of errors in the input.
1320    pub fn into_result(self) -> Result<(), FederationError> {
1321        match self.errors.len().cmp(&1) {
1322            Ordering::Less => Ok(()),
1323            Ordering::Equal => Err(self.errors[0].clone().into()),
1324            Ordering::Greater => Err(self.into()),
1325        }
1326    }
1327}
1328
1329// We didn't track errors addition precisely pre-2.0 and tracking it now has an unclear ROI, so we
1330// just mark all the error code that predates 2.0 as 0.x.
1331const FED1_CODE: &str = "0.x";
1332
1333#[derive(Debug, Clone)]
1334pub struct ErrorCodeMetadata {
1335    pub added_in: &'static str,
1336    pub replaces: &'static [&'static str],
1337}
1338
1339#[derive(Debug)]
1340pub struct ErrorCodeDefinition {
1341    code: String,
1342    // PORT_NOTE: Known as "description" in the JS code. The name was changed to distinguish it from
1343    // Error.description().
1344    doc_description: String,
1345    metadata: ErrorCodeMetadata,
1346}
1347
1348impl ErrorCodeDefinition {
1349    fn new(code: String, doc_description: String, metadata: Option<ErrorCodeMetadata>) -> Self {
1350        Self {
1351            code,
1352            doc_description,
1353            metadata: metadata.unwrap_or_else(|| DEFAULT_METADATA.clone()),
1354        }
1355    }
1356
1357    pub fn code(&self) -> &str {
1358        &self.code
1359    }
1360
1361    pub fn doc_description(&self) -> &str {
1362        &self.doc_description
1363    }
1364
1365    pub fn metadata(&self) -> &ErrorCodeMetadata {
1366        &self.metadata
1367    }
1368}
1369
1370/*
1371 * Most codes currently originate from the initial fed 2 release so we use this for convenience.
1372 * This can be changed later, inline versions everywhere, if that becomes irrelevant.
1373 */
1374static DEFAULT_METADATA: ErrorCodeMetadata = ErrorCodeMetadata {
1375    added_in: "2.0.0",
1376    replaces: &[],
1377};
1378
1379struct ErrorCodeCategory<TElement: Clone + Into<String>> {
1380    // Fn(element: TElement) -> String
1381    extract_code: Box<dyn 'static + Send + Sync + Fn(TElement) -> String>,
1382    // Fn(element: TElement) -> String
1383    make_doc_description: Box<dyn 'static + Send + Sync + Fn(TElement) -> String>,
1384    metadata: ErrorCodeMetadata,
1385}
1386
1387impl<TElement: Clone + Into<String>> ErrorCodeCategory<TElement> {
1388    fn new(
1389        extract_code: Box<dyn 'static + Send + Sync + Fn(TElement) -> String>,
1390        make_doc_description: Box<dyn 'static + Send + Sync + Fn(TElement) -> String>,
1391        metadata: Option<ErrorCodeMetadata>,
1392    ) -> Self {
1393        Self {
1394            extract_code,
1395            make_doc_description,
1396            metadata: metadata.unwrap_or_else(|| DEFAULT_METADATA.clone()),
1397        }
1398    }
1399
1400    // PORT_NOTE: The Typescript type in the JS code only has get(), but I also added createCode()
1401    // here since it's used in the return type of makeErrorCodeCategory().
1402    fn create_code(&self, element: TElement) -> ErrorCodeDefinition {
1403        ErrorCodeDefinition::new(
1404            (self.extract_code)(element.clone()),
1405            (self.make_doc_description)(element),
1406            Some(self.metadata.clone()),
1407        )
1408    }
1409}
1410
1411impl ErrorCodeCategory<String> {
1412    fn new_federation_directive(
1413        code_suffix: String,
1414        make_doc_description: Box<dyn 'static + Send + Sync + Fn(String) -> String>,
1415        metadata: Option<ErrorCodeMetadata>,
1416    ) -> Self {
1417        Self::new(
1418            Box::new(move |element: String| format!("{}_{}", element.to_uppercase(), code_suffix)),
1419            make_doc_description,
1420            metadata,
1421        )
1422    }
1423}
1424
1425static INVALID_GRAPHQL: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1426    ErrorCodeDefinition::new(
1427        "INVALID_GRAPHQL".to_owned(),
1428        "A schema is invalid GraphQL: it violates one of the rule of the specification.".to_owned(),
1429        None,
1430    )
1431});
1432static DIRECTIVE_DEFINITION_INVALID: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1433    ErrorCodeDefinition::new(
1434        "DIRECTIVE_DEFINITION_INVALID".to_owned(),
1435        "A built-in or federation directive has an invalid definition in the schema.".to_owned(),
1436        Some(ErrorCodeMetadata {
1437            replaces: &["TAG_DEFINITION_INVALID"],
1438            ..DEFAULT_METADATA.clone()
1439        }),
1440    )
1441});
1442
1443static TYPE_DEFINITION_INVALID: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1444    ErrorCodeDefinition::new(
1445        "TYPE_DEFINITION_INVALID".to_owned(),
1446        "A built-in or federation type has an invalid definition in the schema.".to_owned(),
1447        None,
1448    )
1449});
1450
1451static UNSUPPORTED_LINKED_FEATURE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1452    ErrorCodeDefinition::new(
1453        "UNSUPPORTED_LINKED_FEATURE".to_owned(),
1454        "Indicates that a feature used in a @link is either unsupported or is used with unsupported options.".to_owned(),
1455        None,
1456    )
1457});
1458
1459static UNKNOWN_FEDERATION_LINK_VERSION: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1460    ErrorCodeDefinition::new(
1461        "UNKNOWN_FEDERATION_LINK_VERSION".to_owned(),
1462        "The version of federation in a @link directive on the schema is unknown.".to_owned(),
1463        None,
1464    )
1465});
1466
1467static UNKNOWN_LINK_VERSION: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1468    ErrorCodeDefinition::new(
1469        "UNKNOWN_LINK_VERSION".to_owned(),
1470        "The version of @link set on the schema is unknown.".to_owned(),
1471        Some(ErrorCodeMetadata {
1472            added_in: "2.1.0",
1473            replaces: &[],
1474        }),
1475    )
1476});
1477
1478static FIELDS_HAS_ARGS: LazyLock<ErrorCodeCategory<String>> = LazyLock::new(|| {
1479    ErrorCodeCategory::new_federation_directive(
1480        "FIELDS_HAS_ARGS".to_owned(),
1481        Box::new(|directive| {
1482            format!(
1483                "The `fields` argument of a `@{directive}` directive includes a field defined with arguments (which is not currently supported)."
1484            )
1485        }),
1486        None,
1487    )
1488});
1489
1490static KEY_FIELDS_HAS_ARGS: LazyLock<ErrorCodeDefinition> =
1491    LazyLock::new(|| FIELDS_HAS_ARGS.create_code("key".to_owned()));
1492
1493static PROVIDES_FIELDS_HAS_ARGS: LazyLock<ErrorCodeDefinition> =
1494    LazyLock::new(|| FIELDS_HAS_ARGS.create_code("provides".to_owned()));
1495
1496static DIRECTIVE_FIELDS_MISSING_EXTERNAL: LazyLock<ErrorCodeCategory<String>> = LazyLock::new(
1497    || {
1498        ErrorCodeCategory::new_federation_directive(
1499            "FIELDS_MISSING_EXTERNAL".to_owned(),
1500            Box::new(|directive| {
1501                format!(
1502                    "The `fields` argument of a `@{directive}` directive includes a field that is not marked as `@external`."
1503                )
1504            }),
1505            Some(ErrorCodeMetadata {
1506                added_in: FED1_CODE,
1507                replaces: &[],
1508            }),
1509        )
1510    },
1511);
1512
1513static PROVIDES_FIELDS_MISSING_EXTERNAL: LazyLock<ErrorCodeDefinition> =
1514    LazyLock::new(|| DIRECTIVE_FIELDS_MISSING_EXTERNAL.create_code("provides".to_owned()));
1515static REQUIRES_FIELDS_MISSING_EXTERNAL: LazyLock<ErrorCodeDefinition> =
1516    LazyLock::new(|| DIRECTIVE_FIELDS_MISSING_EXTERNAL.create_code("requires".to_owned()));
1517
1518static DIRECTIVE_UNSUPPORTED_ON_INTERFACE: LazyLock<ErrorCodeCategory<String>> =
1519    LazyLock::new(|| {
1520        ErrorCodeCategory::new_federation_directive(
1521            "UNSUPPORTED_ON_INTERFACE".to_owned(),
1522            Box::new(|directive| {
1523                let suffix = if directive == "key" {
1524                    "only supported when @linking to federation 2.3+"
1525                } else {
1526                    "not (yet) supported"
1527                };
1528                format!("A `@{directive}` directive is used on an interface, which is {suffix}.")
1529            }),
1530            None,
1531        )
1532    });
1533
1534static KEY_UNSUPPORTED_ON_INTERFACE: LazyLock<ErrorCodeDefinition> =
1535    LazyLock::new(|| DIRECTIVE_UNSUPPORTED_ON_INTERFACE.create_code("key".to_owned()));
1536static PROVIDES_UNSUPPORTED_ON_INTERFACE: LazyLock<ErrorCodeDefinition> =
1537    LazyLock::new(|| DIRECTIVE_UNSUPPORTED_ON_INTERFACE.create_code("provides".to_owned()));
1538static REQUIRES_UNSUPPORTED_ON_INTERFACE: LazyLock<ErrorCodeDefinition> =
1539    LazyLock::new(|| DIRECTIVE_UNSUPPORTED_ON_INTERFACE.create_code("requires".to_owned()));
1540
1541static DIRECTIVE_IN_FIELDS_ARG: LazyLock<ErrorCodeCategory<String>> = LazyLock::new(|| {
1542    ErrorCodeCategory::new_federation_directive(
1543        "DIRECTIVE_IN_FIELDS_ARG".to_owned(),
1544        Box::new(|directive| {
1545            format!(
1546                "The `fields` argument of a `@{directive}` directive includes some directive applications. This is not supported"
1547            )
1548        }),
1549        Some(ErrorCodeMetadata {
1550            added_in: "2.1.0",
1551            replaces: &[],
1552        }),
1553    )
1554});
1555
1556static KEY_DIRECTIVE_IN_FIELDS_ARGS: LazyLock<ErrorCodeDefinition> =
1557    LazyLock::new(|| DIRECTIVE_IN_FIELDS_ARG.create_code("key".to_owned()));
1558static PROVIDES_DIRECTIVE_IN_FIELDS_ARGS: LazyLock<ErrorCodeDefinition> =
1559    LazyLock::new(|| DIRECTIVE_IN_FIELDS_ARG.create_code("provides".to_owned()));
1560static REQUIRES_DIRECTIVE_IN_FIELDS_ARGS: LazyLock<ErrorCodeDefinition> =
1561    LazyLock::new(|| DIRECTIVE_IN_FIELDS_ARG.create_code("requires".to_owned()));
1562
1563static EXTERNAL_UNUSED: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1564    ErrorCodeDefinition::new(
1565        "EXTERNAL_UNUSED".to_owned(),
1566        "An `@external` field is not being used by any instance of `@key`, `@requires`, `@provides` or to satisfy an interface implementation.".to_owned(),
1567        Some(ErrorCodeMetadata {
1568            added_in: FED1_CODE,
1569            replaces: &[],
1570        }),
1571)
1572});
1573
1574static TYPE_WITH_ONLY_UNUSED_EXTERNAL: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1575    ErrorCodeDefinition::new(
1576        "TYPE_WITH_ONLY_UNUSED_EXTERNAL".to_owned(),
1577        [
1578            "A federation 1 schema has a composite type comprised only of unused external fields.".to_owned(),
1579            format!("Note that this error can _only_ be raised for federation 1 schema as federation 2 schema do not allow unused external fields (and errors with code {} will be raised in that case).", EXTERNAL_UNUSED.code),
1580            "But when federation 1 schema are automatically migrated to federation 2 ones, unused external fields are automatically removed, and in rare case this can leave a type empty. If that happens, an error with this code will be raised".to_owned()
1581        ].join(" "),
1582        None,
1583)
1584});
1585
1586static PROVIDES_ON_NON_OBJECT_FIELD: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1587    ErrorCodeDefinition::new(
1588        "PROVIDES_ON_NON_OBJECT_FIELD".to_owned(),
1589        "A `@provides` directive is used to mark a field whose base type is not an object type."
1590            .to_owned(),
1591        None,
1592    )
1593});
1594
1595static DIRECTIVE_INVALID_FIELDS_TYPE: LazyLock<ErrorCodeCategory<String>> = LazyLock::new(|| {
1596    ErrorCodeCategory::new_federation_directive(
1597        "INVALID_FIELDS_TYPE".to_owned(),
1598        Box::new(|directive| {
1599            format!(
1600                "The value passed to the `fields` argument of a `@{directive}` directive is not a string."
1601            )
1602        }),
1603        None,
1604    )
1605});
1606
1607static KEY_INVALID_FIELDS_TYPE: LazyLock<ErrorCodeDefinition> =
1608    LazyLock::new(|| DIRECTIVE_INVALID_FIELDS_TYPE.create_code("key".to_owned()));
1609static PROVIDES_INVALID_FIELDS_TYPE: LazyLock<ErrorCodeDefinition> =
1610    LazyLock::new(|| DIRECTIVE_INVALID_FIELDS_TYPE.create_code("provides".to_owned()));
1611static REQUIRES_INVALID_FIELDS_TYPE: LazyLock<ErrorCodeDefinition> =
1612    LazyLock::new(|| DIRECTIVE_INVALID_FIELDS_TYPE.create_code("requires".to_owned()));
1613
1614static DIRECTIVE_INVALID_FIELDS: LazyLock<ErrorCodeCategory<String>> = LazyLock::new(|| {
1615    ErrorCodeCategory::new_federation_directive(
1616        "INVALID_FIELDS".to_owned(),
1617        Box::new(|directive| {
1618            format!(
1619                "The `fields` argument of a `@{directive}` directive is invalid (it has invalid syntax, includes unknown fields, ...)."
1620            )
1621        }),
1622        None,
1623    )
1624});
1625
1626static KEY_INVALID_FIELDS: LazyLock<ErrorCodeDefinition> =
1627    LazyLock::new(|| DIRECTIVE_INVALID_FIELDS.create_code("key".to_owned()));
1628static PROVIDES_INVALID_FIELDS: LazyLock<ErrorCodeDefinition> =
1629    LazyLock::new(|| DIRECTIVE_INVALID_FIELDS.create_code("provides".to_owned()));
1630static REQUIRES_INVALID_FIELDS: LazyLock<ErrorCodeDefinition> =
1631    LazyLock::new(|| DIRECTIVE_INVALID_FIELDS.create_code("requires".to_owned()));
1632
1633static KEY_FIELDS_SELECT_INVALID_TYPE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1634    ErrorCodeDefinition::new(
1635        "KEY_FIELDS_SELECT_INVALID_TYPE".to_owned(),
1636        "The `fields` argument of `@key` directive includes a field whose type is a list, interface, or union type. Fields of these types cannot be part of a `@key`".to_owned(),
1637        Some(ErrorCodeMetadata {
1638            added_in: FED1_CODE,
1639            replaces: &[],
1640        }),
1641)
1642});
1643
1644static ROOT_TYPE_USED: LazyLock<ErrorCodeCategory<SchemaRootKind>> = LazyLock::new(|| {
1645    ErrorCodeCategory::new(
1646        Box::new(|element| {
1647            let kind: String = element.into();
1648            format!("ROOT_{}_USED", kind.to_uppercase())
1649        }),
1650        Box::new(|element| {
1651            let kind: String = element.into();
1652            format!(
1653                "A subgraph's schema defines a type with the name `{kind}`, while also specifying a _different_ type name as the root query object. This is not allowed."
1654            )
1655        }),
1656        Some(ErrorCodeMetadata {
1657            added_in: FED1_CODE,
1658            replaces: &[],
1659        }),
1660    )
1661});
1662
1663static ROOT_QUERY_USED: LazyLock<ErrorCodeDefinition> =
1664    LazyLock::new(|| ROOT_TYPE_USED.create_code(SchemaRootKind::Query));
1665static ROOT_MUTATION_USED: LazyLock<ErrorCodeDefinition> =
1666    LazyLock::new(|| ROOT_TYPE_USED.create_code(SchemaRootKind::Mutation));
1667static ROOT_SUBSCRIPTION_USED: LazyLock<ErrorCodeDefinition> =
1668    LazyLock::new(|| ROOT_TYPE_USED.create_code(SchemaRootKind::Subscription));
1669
1670static INVALID_SUBGRAPH_NAME: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1671    ErrorCodeDefinition::new(
1672        "INVALID_SUBGRAPH_NAME".to_owned(),
1673        "A subgraph name is invalid (subgraph names cannot be a single underscore (\"_\"))."
1674            .to_owned(),
1675        None,
1676    )
1677});
1678
1679static NO_QUERIES: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1680    ErrorCodeDefinition::new(
1681        "NO_QUERIES".to_owned(),
1682        "None of the composed subgraphs expose any query.".to_owned(),
1683        None,
1684    )
1685});
1686
1687static INTERFACE_FIELD_NO_IMPLEM: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1688    ErrorCodeDefinition::new(
1689        "INTERFACE_FIELD_NO_IMPLEM".to_owned(),
1690        "After subgraph merging, an implementation is missing a field of one of the interface it implements (which can happen for valid subgraphs).".to_owned(),
1691        None,
1692    )
1693});
1694
1695static TYPE_KIND_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1696    ErrorCodeDefinition::new(
1697        "TYPE_KIND_MISMATCH".to_owned(),
1698        "A type has the same name in different subgraphs, but a different kind. For instance, one definition is an object type but another is an interface.".to_owned(),
1699        Some(ErrorCodeMetadata {
1700            replaces: &["VALUE_TYPE_KIND_MISMATCH", "EXTENSION_OF_WRONG_KIND", "ENUM_MISMATCH_TYPE"],
1701            ..DEFAULT_METADATA.clone()
1702        }),
1703    )
1704});
1705
1706static EXTERNAL_TYPE_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1707    ErrorCodeDefinition::new(
1708        "EXTERNAL_TYPE_MISMATCH".to_owned(),
1709        "An `@external` field has a type that is incompatible with the declaration(s) of that field in other subgraphs.".to_owned(),
1710        Some(ErrorCodeMetadata {
1711            added_in: FED1_CODE,
1712            replaces: &[],
1713        }),
1714    )
1715});
1716
1717static EXTERNAL_COLLISION_WITH_ANOTHER_DIRECTIVE: LazyLock<ErrorCodeDefinition> =
1718    LazyLock::new(|| {
1719        ErrorCodeDefinition::new(
1720            "EXTERNAL_COLLISION_WITH_ANOTHER_DIRECTIVE".to_owned(),
1721            "The @external directive collides with other directives in some situations.".to_owned(),
1722            Some(ErrorCodeMetadata {
1723                added_in: "2.1.0",
1724                replaces: &[],
1725            }),
1726        )
1727    });
1728
1729static EXTERNAL_ARGUMENT_MISSING: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1730    ErrorCodeDefinition::new(
1731        "EXTERNAL_ARGUMENT_MISSING".to_owned(),
1732        "An `@external` field is missing some arguments present in the declaration(s) of that field in other subgraphs.".to_owned(),
1733        None,
1734    )
1735});
1736
1737static EXTERNAL_ARGUMENT_TYPE_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1738    ErrorCodeDefinition::new(
1739        "EXTERNAL_ARGUMENT_TYPE_MISMATCH".to_owned(),
1740        "An `@external` field declares an argument with a type that is incompatible with the corresponding argument in the declaration(s) of that field in other subgraphs.".to_owned(),
1741        None,
1742    )
1743});
1744
1745static EXTERNAL_ARGUMENT_DEFAULT_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1746    ErrorCodeDefinition::new(
1747        "EXTERNAL_ARGUMENT_DEFAULT_MISMATCH".to_owned(),
1748        "An `@external` field declares an argument with a default that is incompatible with the corresponding argument in the declaration(s) of that field in other subgraphs.".to_owned(),
1749        None,
1750    )
1751});
1752
1753static EXTERNAL_ON_INTERFACE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1754    ErrorCodeDefinition::new(
1755        "EXTERNAL_ON_INTERFACE".to_owned(),
1756        "The field of an interface type is marked with `@external`: as external is about marking field not resolved by the subgraph and as interface field are not resolved (only implementations of those fields are), an \"external\" interface field is nonsensical".to_owned(),
1757        None,
1758    )
1759});
1760
1761static MERGED_DIRECTIVE_APPLICATION_ON_EXTERNAL: LazyLock<ErrorCodeDefinition> = LazyLock::new(
1762    || {
1763        ErrorCodeDefinition::new(
1764        "MERGED_DIRECTIVE_APPLICATION_ON_EXTERNAL".to_owned(),
1765        "In a subgraph, a field is both marked @external and has a merged directive applied to it".to_owned(),
1766        None,
1767    )
1768    },
1769);
1770
1771static FIELD_TYPE_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1772    ErrorCodeDefinition::new(
1773        "FIELD_TYPE_MISMATCH".to_owned(),
1774        "A field has a type that is incompatible with other declarations of that field in other subgraphs.".to_owned(),
1775        Some(ErrorCodeMetadata {
1776            replaces: &["VALUE_TYPE_FIELD_TYPE_MISMATCH"],
1777            ..DEFAULT_METADATA.clone()
1778        }),
1779    )
1780});
1781
1782static FIELD_ARGUMENT_TYPE_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1783    ErrorCodeDefinition::new(
1784        "FIELD_ARGUMENT_TYPE_MISMATCH".to_owned(),
1785        "An argument (of a field/directive) has a type that is incompatible with that of other declarations of that same argument in other subgraphs.".to_owned(),
1786        Some(ErrorCodeMetadata {
1787            replaces: &["VALUE_TYPE_INPUT_VALUE_MISMATCH"],
1788            ..DEFAULT_METADATA.clone()
1789        }),
1790    )
1791});
1792
1793static INPUT_FIELD_DEFAULT_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1794    ErrorCodeDefinition::new(
1795        "INPUT_FIELD_DEFAULT_MISMATCH".to_owned(),
1796        "An input field has a default value that is incompatible with other declarations of that field in other subgraphs.".to_owned(),
1797        None,
1798    )
1799});
1800
1801static FIELD_ARGUMENT_DEFAULT_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1802    ErrorCodeDefinition::new(
1803        "FIELD_ARGUMENT_DEFAULT_MISMATCH".to_owned(),
1804        "An argument (of a field/directive) has a default value that is incompatible with that of other declarations of that same argument in other subgraphs.".to_owned(),
1805        None,
1806    )
1807});
1808
1809static EXTENSION_WITH_NO_BASE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1810    ErrorCodeDefinition::new(
1811        "EXTENSION_WITH_NO_BASE".to_owned(),
1812        "A subgraph is attempting to `extend` a type that is not originally defined in any known subgraph.".to_owned(),
1813        Some(ErrorCodeMetadata {
1814            added_in: FED1_CODE,
1815            replaces: &[],
1816        }),
1817    )
1818});
1819
1820static EXTERNAL_MISSING_ON_BASE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1821    ErrorCodeDefinition::new(
1822        "EXTERNAL_MISSING_ON_BASE".to_owned(),
1823        "A field is marked as `@external` in a subgraph but with no non-external declaration in any other subgraph.".to_owned(),
1824        Some(ErrorCodeMetadata {
1825            added_in: FED1_CODE,
1826            replaces: &[],
1827        }),
1828    )
1829});
1830
1831static INVALID_FIELD_SHARING: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1832    ErrorCodeDefinition::new(
1833        "INVALID_FIELD_SHARING".to_owned(),
1834        "A field that is non-shareable in at least one subgraph is resolved by multiple subgraphs."
1835            .to_owned(),
1836        None,
1837    )
1838});
1839
1840static INVALID_SHAREABLE_USAGE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1841    ErrorCodeDefinition::new(
1842        "INVALID_SHAREABLE_USAGE".to_owned(),
1843        "The `@shareable` federation directive is used in an invalid way.".to_owned(),
1844        Some(ErrorCodeMetadata {
1845            added_in: "2.1.2",
1846            replaces: &[],
1847        }),
1848    )
1849});
1850
1851static INVALID_LINK_DIRECTIVE_USAGE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1852    ErrorCodeDefinition::new(
1853        "INVALID_LINK_DIRECTIVE_USAGE".to_owned(),
1854        "An application of the @link directive is invalid/does not respect the specification."
1855            .to_owned(),
1856        None,
1857    )
1858});
1859
1860static INVALID_LINK_IDENTIFIER: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1861    ErrorCodeDefinition::new(
1862        "INVALID_LINK_IDENTIFIER".to_owned(),
1863        "A url/version for a @link feature is invalid/does not respect the specification."
1864            .to_owned(),
1865        Some(ErrorCodeMetadata {
1866            added_in: "2.1.0",
1867            replaces: &[],
1868        }),
1869    )
1870});
1871
1872static LINK_IMPORT_NAME_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1873    ErrorCodeDefinition::new(
1874        "LINK_IMPORT_NAME_MISMATCH".to_owned(),
1875        "The import name for a merged directive (as declared by the relevant `@link(import:)` argument) is inconsistent between subgraphs.".to_owned(),
1876        None,
1877    )
1878});
1879
1880static REFERENCED_INACCESSIBLE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1881    ErrorCodeDefinition::new(
1882        "REFERENCED_INACCESSIBLE".to_owned(),
1883        "An element is marked as @inaccessible but is referenced by an element visible in the API schema.".to_owned(),
1884        None,
1885    )
1886});
1887
1888static DEFAULT_VALUE_USES_INACCESSIBLE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1889    ErrorCodeDefinition::new(
1890        "DEFAULT_VALUE_USES_INACCESSIBLE".to_owned(),
1891        "An element is marked as @inaccessible but is used in the default value of an element visible in the API schema.".to_owned(),
1892        None,
1893    )
1894});
1895
1896static QUERY_ROOT_TYPE_INACCESSIBLE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1897    ErrorCodeDefinition::new(
1898        "QUERY_ROOT_TYPE_INACCESSIBLE".to_owned(),
1899        "An element is marked as @inaccessible but is the query root type, which must be visible in the API schema.".to_owned(),
1900        None,
1901    )
1902});
1903
1904static REQUIRED_INACCESSIBLE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1905    ErrorCodeDefinition::new(
1906        "REQUIRED_INACCESSIBLE".to_owned(),
1907        "An element is marked as @inaccessible but is required by an element visible in the API schema.".to_owned(),
1908        None,
1909    )
1910});
1911
1912static IMPLEMENTED_BY_INACCESSIBLE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1913    ErrorCodeDefinition::new(
1914        "IMPLEMENTED_BY_INACCESSIBLE".to_owned(),
1915        "An element is marked as @inaccessible but implements an element visible in the API schema.".to_owned(),
1916        None,
1917    )
1918});
1919
1920static DISALLOWED_INACCESSIBLE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1921    ErrorCodeDefinition::new(
1922        "DISALLOWED_INACCESSIBLE".to_owned(),
1923        "An element is marked as @inaccessible that is not allowed to be @inaccessible.".to_owned(),
1924        None,
1925    )
1926});
1927
1928static ONLY_INACCESSIBLE_CHILDREN: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1929    ErrorCodeDefinition::new(
1930        "ONLY_INACCESSIBLE_CHILDREN".to_owned(),
1931        "A type visible in the API schema has only @inaccessible children.".to_owned(),
1932        None,
1933    )
1934});
1935
1936static REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH: LazyLock<ErrorCodeDefinition> = LazyLock::new(
1937    || {
1938        ErrorCodeDefinition::new(
1939        "REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH".to_owned(),
1940        "A field of an input object type is mandatory in some subgraphs, but the field is not defined in all the subgraphs that define the input object type.".to_owned(),
1941        None,
1942    )
1943    },
1944);
1945
1946static REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH: LazyLock<ErrorCodeDefinition> = LazyLock::new(
1947    || {
1948        ErrorCodeDefinition::new(
1949        "REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH".to_owned(),
1950        "An argument of a field or directive definition is mandatory in some subgraphs, but the argument is not defined in all the subgraphs that define the field or directive definition.".to_owned(),
1951        None,
1952    )
1953    },
1954);
1955
1956static EMPTY_MERGED_INPUT_TYPE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1957    ErrorCodeDefinition::new(
1958        "EMPTY_MERGED_INPUT_TYPE".to_owned(),
1959        "An input object type has no field common to all the subgraphs that define the type. Merging that type would result in an invalid empty input object type.".to_owned(),
1960        None,
1961    )
1962});
1963
1964static INPUT_FIELD_MERGE_FAILED: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1965    ErrorCodeDefinition::new(
1966        "INPUT_FIELD_MERGE_FAILED".to_owned(),
1967        "Failed to merge an input object field due to incompatible definitions across subgraphs."
1968            .to_owned(),
1969        None,
1970    )
1971});
1972
1973static ENUM_VALUE_MISMATCH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1974    ErrorCodeDefinition::new(
1975        "ENUM_VALUE_MISMATCH".to_owned(),
1976        "An enum type that is used as both an input and output type has a value that is not defined in all the subgraphs that define the enum type.".to_owned(),
1977        None,
1978    )
1979});
1980
1981static EMPTY_MERGED_ENUM_TYPE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
1982    ErrorCodeDefinition::new(
1983        "EMPTY_MERGED_ENUM_TYPE".to_owned(),
1984        "An enum type has no value common to all the subgraphs that define the type. Merging that type would result in an invalid empty enum type.".to_owned(),
1985        None,
1986    )
1987});
1988
1989static SHAREABLE_HAS_MISMATCHED_RUNTIME_TYPES: LazyLock<ErrorCodeDefinition> = LazyLock::new(
1990    || {
1991        ErrorCodeDefinition::new(
1992        "SHAREABLE_HAS_MISMATCHED_RUNTIME_TYPES".to_owned(),
1993        "A shareable field return type has mismatched possible runtime types in the subgraphs in which the field is declared. As shared fields must resolve the same way in all subgraphs, this is almost surely a mistake.".to_owned(),
1994        None,
1995    )
1996    },
1997);
1998
1999static SATISFIABILITY_ERROR: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2000    ErrorCodeDefinition::new(
2001        "SATISFIABILITY_ERROR".to_owned(),
2002        "Subgraphs can be merged, but the resulting supergraph API would have queries that cannot be satisfied by those subgraphs.".to_owned(),
2003        None,
2004    )
2005});
2006
2007static MAX_VALIDATION_SUBGRAPH_PATHS_EXCEEDED: LazyLock<ErrorCodeDefinition> =
2008    LazyLock::new(|| {
2009        ErrorCodeDefinition::new(
2010            "MAX_VALIDATION_SUBGRAPH_PATHS_EXCEEDED".to_owned(),
2011            "The maximum number of validation subgraph paths has been exceeded.".to_owned(),
2012            Some(ErrorCodeMetadata {
2013                added_in: "2.8.0",
2014                replaces: &[],
2015            }),
2016        )
2017    });
2018
2019static OVERRIDE_FROM_SELF_ERROR: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2020    ErrorCodeDefinition::new(
2021        "OVERRIDE_FROM_SELF_ERROR".to_owned(),
2022        "Field with `@override` directive has \"from\" location that references its own subgraph."
2023            .to_owned(),
2024        None,
2025    )
2026});
2027
2028static OVERRIDE_SOURCE_HAS_OVERRIDE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2029    ErrorCodeDefinition::new(
2030        "OVERRIDE_SOURCE_HAS_OVERRIDE".to_owned(),
2031        "Field which is overridden to another subgraph is also marked @override.".to_owned(),
2032        None,
2033    )
2034});
2035
2036static OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE: LazyLock<ErrorCodeDefinition> = LazyLock::new(
2037    || {
2038        ErrorCodeDefinition::new(
2039        "OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE".to_owned(),
2040        "The @override directive cannot be used on external fields, nor to override fields with either @external, @provides, or @requires.".to_owned(),
2041        None,
2042    )
2043    },
2044);
2045
2046static OVERRIDE_ON_INTERFACE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2047    ErrorCodeDefinition::new(
2048        "OVERRIDE_ON_INTERFACE".to_owned(),
2049        "The @override directive cannot be used on the fields of an interface type.".to_owned(),
2050        Some(ErrorCodeMetadata {
2051            added_in: "2.3.0",
2052            replaces: &[],
2053        }),
2054    )
2055});
2056
2057static OVERRIDE_LABEL_INVALID: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2058    ErrorCodeDefinition::new(
2059        "OVERRIDE_LABEL_INVALID".to_owned(),
2060        r#"The @override directive `label` argument must match the pattern /^[a-zA-Z][a-zA-Z0-9_\-:./]*$/ or /^percent\((\d{1,2}(\.\d{1,8})?|100)\)$/"#.to_owned(),
2061        Some(ErrorCodeMetadata {
2062            added_in: "2.7.0",
2063            replaces: &[],
2064        }),
2065    )
2066});
2067
2068static UNSUPPORTED_FEATURE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2069    ErrorCodeDefinition::new(
2070        "UNSUPPORTED_FEATURE".to_owned(),
2071        "Indicates an error due to feature currently unsupported by federation.".to_owned(),
2072        Some(ErrorCodeMetadata {
2073            added_in: "2.1.0",
2074            replaces: &[],
2075        }),
2076    )
2077});
2078
2079static INVALID_FEDERATION_SUPERGRAPH: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2080    ErrorCodeDefinition::new(
2081        "INVALID_FEDERATION_SUPERGRAPH".to_owned(),
2082        "Indicates that a schema provided for an Apollo Federation supergraph is not a valid supergraph schema.".to_owned(),
2083        Some(ErrorCodeMetadata {
2084            added_in: "2.1.0",
2085            replaces: &[],
2086        }),
2087    )
2088});
2089
2090static DOWNSTREAM_SERVICE_ERROR: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2091    ErrorCodeDefinition::new(
2092        "DOWNSTREAM_SERVICE_ERROR".to_owned(),
2093        "Indicates an error in a subgraph service query during query execution in a federated service.".to_owned(),
2094        Some(ErrorCodeMetadata {
2095            added_in: FED1_CODE,
2096            replaces: &[],
2097        }),
2098    )
2099});
2100
2101static DIRECTIVE_COMPOSITION_ERROR: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2102    ErrorCodeDefinition::new(
2103        "DIRECTIVE_COMPOSITION_ERROR".to_owned(),
2104        "Error when composing custom directives.".to_owned(),
2105        Some(ErrorCodeMetadata {
2106            added_in: "2.1.0",
2107            replaces: &[],
2108        }),
2109    )
2110});
2111
2112static INTERFACE_OBJECT_USAGE_ERROR: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2113    ErrorCodeDefinition::new(
2114        "INTERFACE_OBJECT_USAGE_ERROR".to_owned(),
2115        "Error in the usage of the @interfaceObject directive.".to_owned(),
2116        Some(ErrorCodeMetadata {
2117            added_in: "2.3.0",
2118            replaces: &[],
2119        }),
2120    )
2121});
2122
2123static INTERFACE_KEY_NOT_ON_IMPLEMENTATION: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2124    ErrorCodeDefinition::new(
2125        "INTERFACE_KEY_NOT_ON_IMPLEMENTATION".to_owned(),
2126        "A `@key` is defined on an interface type, but is not defined (or is not resolvable) on at least one of the interface implementations".to_owned(),
2127        Some(ErrorCodeMetadata {
2128            added_in: "2.3.0",
2129            replaces: &[],
2130        }),
2131    )
2132});
2133
2134static INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE: LazyLock<ErrorCodeDefinition> = LazyLock::new(
2135    || {
2136        ErrorCodeDefinition::new(
2137        "INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE".to_owned(),
2138        "A subgraph has a `@key` on an interface type, but that subgraph does not define an implementation (in the supergraph) of that interface".to_owned(),
2139        Some(ErrorCodeMetadata {
2140            added_in: "2.3.0",
2141            replaces: &[],
2142        }),
2143    )
2144    },
2145);
2146
2147static INTERNAL: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2148    ErrorCodeDefinition::new(
2149        "INTERNAL".to_owned(),
2150        "An internal federation error occured.".to_owned(),
2151        None,
2152    )
2153});
2154
2155static ERROR_CODE_MISSING: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2156    ErrorCodeDefinition::new(
2157        "ERROR_CODE_MISSING".to_owned(),
2158        "An internal federation error occurred when translating a federation error into an error code".to_owned(),
2159        None,
2160    )
2161});
2162
2163static UNSUPPORTED_FEDERATION_VERSION: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2164    ErrorCodeDefinition::new(
2165        "UNSUPPORTED_FEDERATION_VERSION".to_owned(),
2166        "Supergraphs composed with federation version 1 are not supported. Please recompose your supergraph with federation version 2 or greater".to_owned(),
2167        None,
2168    )
2169});
2170
2171static UNSUPPORTED_FEDERATION_DIRECTIVE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2172    ErrorCodeDefinition::new(
2173        "UNSUPPORTED_FEDERATION_DIRECTIVE".to_owned(),
2174        "Indicates that the specified specification version is outside of supported range"
2175            .to_owned(),
2176        None,
2177    )
2178});
2179
2180static QUERY_PLAN_COMPLEXITY_EXCEEDED: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2181    ErrorCodeDefinition::new(
2182        "QUERY_PLAN_COMPLEXITY_EXCEEDED".to_owned(),
2183        "Indicates that provided query has too many possible ways to generate a plan and cannot be planned in a reasonable amount of time"
2184            .to_owned(),
2185        None,
2186    )
2187});
2188
2189static NO_PLAN_FOUND_WITH_DISABLED_SUBGRAPHS: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2190    ErrorCodeDefinition::new(
2191        "NO_PLAN_FOUND_WITH_DISABLED_SUBGRAPHS".to_owned(),
2192        "Indicates that the provided query could not be query planned due to subgraphs being disabled"
2193            .to_owned(),
2194        None,
2195    )
2196});
2197
2198static COST_APPLIED_TO_INTERFACE_FIELD: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2199    ErrorCodeDefinition::new(
2200        "COST_APPLIED_TO_INTERFACE_FIELD".to_owned(),
2201        "The `@cost` directive must be applied to concrete types".to_owned(),
2202        Some(ErrorCodeMetadata {
2203            added_in: "2.9.2",
2204            replaces: &[],
2205        }),
2206    )
2207});
2208
2209static LIST_SIZE_APPLIED_TO_NON_LIST: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2210    ErrorCodeDefinition::new(
2211        "LIST_SIZE_APPLIED_TO_NON_LIST".to_owned(),
2212        "The `@listSize` directive must be applied to list types".to_owned(),
2213        Some(ErrorCodeMetadata {
2214            added_in: "2.9.2",
2215            replaces: &[],
2216        }),
2217    )
2218});
2219
2220static LIST_SIZE_INVALID_ASSUMED_SIZE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2221    ErrorCodeDefinition::new(
2222        "LIST_SIZE_INVALID_ASSUMED_SIZE".to_owned(),
2223        "The `@listSize` directive assumed size cannot be negative".to_owned(),
2224        Some(ErrorCodeMetadata {
2225            added_in: "2.9.2",
2226            replaces: &[],
2227        }),
2228    )
2229});
2230
2231static LIST_SIZE_INVALID_SLICING_ARGUMENT: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2232    ErrorCodeDefinition::new(
2233        "LIST_SIZE_INVALID_SLICING_ARGUMENT".to_owned(),
2234        "The `@listSize` directive must have existing integer slicing arguments".to_owned(),
2235        Some(ErrorCodeMetadata {
2236            added_in: "2.9.2",
2237            replaces: &[],
2238        }),
2239    )
2240});
2241
2242static LIST_SIZE_INVALID_SIZED_FIELD: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2243    ErrorCodeDefinition::new(
2244        "LIST_SIZE_INVALID_SIZED_FIELD".to_owned(),
2245        "The `@listSize` directive must reference existing list fields as sized fields".to_owned(),
2246        Some(ErrorCodeMetadata {
2247            added_in: "2.9.2",
2248            replaces: &[],
2249        }),
2250    )
2251});
2252
2253static CONTEXT_NAME_CONTAINS_UNDERSCORE: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2254    ErrorCodeDefinition::new(
2255        "CONTEXT_NAME_CONTAINS_UNDERSCORE".to_owned(),
2256        "Context name is invalid.".to_owned(),
2257        Some(ErrorCodeMetadata {
2258            added_in: "2.8.0",
2259            replaces: &[],
2260        }),
2261    )
2262});
2263
2264static CONTEXT_NAME_INVALID: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2265    ErrorCodeDefinition::new(
2266        "CONTEXT_NAME_INVALID".to_owned(),
2267        "Context name is invalid.".to_owned(),
2268        Some(ErrorCodeMetadata {
2269            added_in: "2.8.0",
2270            replaces: &[],
2271        }),
2272    )
2273});
2274
2275static CONTEXT_NOT_SET: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2276    ErrorCodeDefinition::new(
2277        "CONTEXT_NOT_SET".to_owned(),
2278        "Context is never set for context trying to be used".to_owned(),
2279        Some(ErrorCodeMetadata {
2280            added_in: "2.8.0",
2281            replaces: &[],
2282        }),
2283    )
2284});
2285
2286static NO_CONTEXT_REFERENCED: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2287    ErrorCodeDefinition::new(
2288        "NO_CONTEXT_REFERENCED".to_owned(),
2289        "Selection in @fromContext field argument does not reference a context".to_owned(),
2290        Some(ErrorCodeMetadata {
2291            added_in: "2.8.0",
2292            replaces: &[],
2293        }),
2294    )
2295});
2296
2297static NO_SELECTION_FOR_CONTEXT: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2298    ErrorCodeDefinition::new(
2299        "NO_SELECTION_FOR_CONTEXT".to_owned(),
2300        "field parameter in @fromContext must contain a selection set".to_owned(),
2301        Some(ErrorCodeMetadata {
2302            added_in: "2.8.0",
2303            replaces: &[],
2304        }),
2305    )
2306});
2307
2308static CONTEXT_NO_RESOLVABLE_KEY: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2309    ErrorCodeDefinition::new(
2310        "CONTEXT_NO_RESOLVABLE_KEY".to_owned(),
2311        "If an ObjectType uses a @fromContext, at least one of its keys must be resolvable"
2312            .to_owned(),
2313        Some(ErrorCodeMetadata {
2314            added_in: "2.8.0",
2315            replaces: &[],
2316        }),
2317    )
2318});
2319
2320static CONTEXT_SELECTION_INVALID: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2321    ErrorCodeDefinition::new(
2322        "CONTEXT_SELECTION_INVALID".to_owned(),
2323        "The selection set is invalid".to_owned(),
2324        Some(ErrorCodeMetadata {
2325            added_in: "2.8.0",
2326            replaces: &[],
2327        }),
2328    )
2329});
2330
2331static INVALID_TAG_NAME: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2332    ErrorCodeDefinition::new(
2333        "INVALID_TAG_NAME".to_owned(),
2334        "Invalid value for argument \"name\" in application of @tag.".to_owned(),
2335        Some(ErrorCodeMetadata {
2336            added_in: "2.0.0",
2337            replaces: &[],
2338        }),
2339    )
2340});
2341
2342static CONTEXTUAL_ARGUMENT_NOT_CONTEXTUAL_IN_ALL_SUBGRAPHS: LazyLock<ErrorCodeDefinition> =
2343    LazyLock::new(|| {
2344        ErrorCodeDefinition::new(
2345            "CONTEXTUAL_ARGUMENT_NOT_CONTEXTUAL_IN_ALL_SUBGRAPHS".to_owned(),
2346            "Argument on field is marked contextual in only some subgraphs".to_owned(),
2347            Some(ErrorCodeMetadata {
2348                added_in: "2.7.0",
2349                replaces: &[],
2350            }),
2351        )
2352    });
2353
2354static QUERY_ROOT_MISSING: LazyLock<ErrorCodeDefinition> = LazyLock::new(|| {
2355    ErrorCodeDefinition::new(
2356        "QUERY_ROOT_MISSING".to_owned(),
2357        "The schema has no query root type.".to_owned(),
2358        Some(ErrorCodeMetadata {
2359            added_in: "2.0.0",
2360            replaces: &[],
2361        }),
2362    )
2363});
2364
2365#[derive(Debug, PartialEq, strum_macros::EnumIter)]
2366pub enum ErrorCode {
2367    ErrorCodeMissing,
2368    Internal,
2369    ExtensionWithNoBase,
2370    InvalidGraphQL,
2371    DirectiveDefinitionInvalid,
2372    TypeDefinitionInvalid,
2373    UnsupportedLinkedFeature,
2374    UnknownFederationLinkVersion,
2375    UnknownLinkVersion,
2376    KeyFieldsHasArgs,
2377    ProvidesFieldsHasArgs,
2378    ProvidesFieldsMissingExternal,
2379    RequiresFieldsMissingExternal,
2380    KeyUnsupportedOnInterface,
2381    ProvidesUnsupportedOnInterface,
2382    RequiresUnsupportedOnInterface,
2383    KeyDirectiveInFieldsArgs,
2384    ProvidesDirectiveInFieldsArgs,
2385    RequiresDirectiveInFieldsArgs,
2386    ExternalUnused,
2387    TypeWithOnlyUnusedExternal,
2388    ProvidesOnNonObjectField,
2389    KeyInvalidFieldsType,
2390    ProvidesInvalidFieldsType,
2391    RequiresInvalidFieldsType,
2392    KeyInvalidFields,
2393    ProvidesInvalidFields,
2394    RequiresInvalidFields,
2395    KeyFieldsSelectInvalidType,
2396    RootQueryUsed,
2397    RootMutationUsed,
2398    RootSubscriptionUsed,
2399    InvalidSubgraphName,
2400    NoQueries,
2401    InterfaceFieldNoImplem,
2402    TypeKindMismatch,
2403    ExternalTypeMismatch,
2404    ExternalCollisionWithAnotherDirective,
2405    ExternalArgumentMissing,
2406    ExternalArgumentTypeMismatch,
2407    ExternalArgumentDefaultMismatch,
2408    ExternalOnInterface,
2409    MergedDirectiveApplicationOnExternal,
2410    FieldTypeMismatch,
2411    FieldArgumentTypeMismatch,
2412    InputFieldDefaultMismatch,
2413    FieldArgumentDefaultMismatch,
2414    ExternalMissingOnBase,
2415    InvalidFieldSharing,
2416    InvalidShareableUsage,
2417    InvalidLinkDirectiveUsage,
2418    InvalidLinkIdentifier,
2419    LinkImportNameMismatch,
2420    ReferencedInaccessible,
2421    DefaultValueUsesInaccessible,
2422    QueryRootTypeInaccessible,
2423    RequiredInaccessible,
2424    ImplementedByInaccessible,
2425    DisallowedInaccessible,
2426    OnlyInaccessibleChildren,
2427    RequiredInputFieldMissingInSomeSubgraph,
2428    RequiredArgumentMissingInSomeSubgraph,
2429    EmptyMergedInputType,
2430    InputFieldMergeFailed,
2431    EnumValueMismatch,
2432    EmptyMergedEnumType,
2433    ShareableHasMismatchedRuntimeTypes,
2434    SatisfiabilityError,
2435    MaxValidationSubgraphPathsExceeded,
2436    OverrideFromSelfError,
2437    OverrideSourceHasOverride,
2438    OverrideCollisionWithAnotherDirective,
2439    OverrideOnInterface,
2440    UnsupportedFeature,
2441    InvalidFederationSupergraph,
2442    DownstreamServiceError,
2443    DirectiveCompositionError,
2444    InterfaceObjectUsageError,
2445    InterfaceKeyNotOnImplementation,
2446    InterfaceKeyMissingImplementationType,
2447    UnsupportedFederationVersion,
2448    UnsupportedFederationDirective,
2449    QueryPlanComplexityExceededError,
2450    NoPlanFoundWithDisabledSubgraphs,
2451    CostAppliedToInterfaceField,
2452    ListSizeAppliedToNonList,
2453    ListSizeInvalidAssumedSize,
2454    ListSizeInvalidSlicingArgument,
2455    ListSizeInvalidSizedField,
2456    ContextNameInvalid,
2457    ContextNameContainsUnderscore,
2458    ContextNotSet,
2459    NoContextReferenced,
2460    NoSelectionForContext,
2461    ContextNoResolvableKey,
2462    ContextSelectionInvalid,
2463    InvalidTagName,
2464    OverrideLabelInvalid,
2465    ContextualArgumentNotContextualInAllSubgraphs,
2466    QueryRootMissing,
2467}
2468
2469impl ErrorCode {
2470    pub fn definition(&self) -> &'static ErrorCodeDefinition {
2471        match self {
2472            ErrorCode::Internal => &INTERNAL,
2473            ErrorCode::ExtensionWithNoBase => &EXTENSION_WITH_NO_BASE,
2474            ErrorCode::InvalidGraphQL => &INVALID_GRAPHQL,
2475            ErrorCode::DirectiveDefinitionInvalid => &DIRECTIVE_DEFINITION_INVALID,
2476            ErrorCode::TypeDefinitionInvalid => &TYPE_DEFINITION_INVALID,
2477            ErrorCode::UnsupportedLinkedFeature => &UNSUPPORTED_LINKED_FEATURE,
2478            ErrorCode::UnknownFederationLinkVersion => &UNKNOWN_FEDERATION_LINK_VERSION,
2479            ErrorCode::UnknownLinkVersion => &UNKNOWN_LINK_VERSION,
2480            ErrorCode::KeyFieldsHasArgs => &KEY_FIELDS_HAS_ARGS,
2481            ErrorCode::ProvidesFieldsHasArgs => &PROVIDES_FIELDS_HAS_ARGS,
2482            ErrorCode::ProvidesFieldsMissingExternal => &PROVIDES_FIELDS_MISSING_EXTERNAL,
2483            ErrorCode::RequiresFieldsMissingExternal => &REQUIRES_FIELDS_MISSING_EXTERNAL,
2484            ErrorCode::KeyUnsupportedOnInterface => &KEY_UNSUPPORTED_ON_INTERFACE,
2485            ErrorCode::ProvidesUnsupportedOnInterface => &PROVIDES_UNSUPPORTED_ON_INTERFACE,
2486            ErrorCode::RequiresUnsupportedOnInterface => &REQUIRES_UNSUPPORTED_ON_INTERFACE,
2487            ErrorCode::KeyDirectiveInFieldsArgs => &KEY_DIRECTIVE_IN_FIELDS_ARGS,
2488            ErrorCode::ProvidesDirectiveInFieldsArgs => &PROVIDES_DIRECTIVE_IN_FIELDS_ARGS,
2489            ErrorCode::RequiresDirectiveInFieldsArgs => &REQUIRES_DIRECTIVE_IN_FIELDS_ARGS,
2490            ErrorCode::ExternalUnused => &EXTERNAL_UNUSED,
2491            ErrorCode::ExternalCollisionWithAnotherDirective => {
2492                &EXTERNAL_COLLISION_WITH_ANOTHER_DIRECTIVE
2493            }
2494            ErrorCode::TypeWithOnlyUnusedExternal => &TYPE_WITH_ONLY_UNUSED_EXTERNAL,
2495            ErrorCode::ProvidesOnNonObjectField => &PROVIDES_ON_NON_OBJECT_FIELD,
2496            ErrorCode::KeyInvalidFieldsType => &KEY_INVALID_FIELDS_TYPE,
2497            ErrorCode::ProvidesInvalidFieldsType => &PROVIDES_INVALID_FIELDS_TYPE,
2498            ErrorCode::RequiresInvalidFieldsType => &REQUIRES_INVALID_FIELDS_TYPE,
2499            ErrorCode::KeyInvalidFields => &KEY_INVALID_FIELDS,
2500            ErrorCode::ProvidesInvalidFields => &PROVIDES_INVALID_FIELDS,
2501            ErrorCode::RequiresInvalidFields => &REQUIRES_INVALID_FIELDS,
2502            ErrorCode::KeyFieldsSelectInvalidType => &KEY_FIELDS_SELECT_INVALID_TYPE,
2503            ErrorCode::RootQueryUsed => &ROOT_QUERY_USED,
2504            ErrorCode::RootMutationUsed => &ROOT_MUTATION_USED,
2505            ErrorCode::RootSubscriptionUsed => &ROOT_SUBSCRIPTION_USED,
2506            ErrorCode::InvalidSubgraphName => &INVALID_SUBGRAPH_NAME,
2507            ErrorCode::NoQueries => &NO_QUERIES,
2508            ErrorCode::InterfaceFieldNoImplem => &INTERFACE_FIELD_NO_IMPLEM,
2509            ErrorCode::TypeKindMismatch => &TYPE_KIND_MISMATCH,
2510            ErrorCode::ExternalTypeMismatch => &EXTERNAL_TYPE_MISMATCH,
2511            ErrorCode::ExternalArgumentMissing => &EXTERNAL_ARGUMENT_MISSING,
2512            ErrorCode::ExternalArgumentTypeMismatch => &EXTERNAL_ARGUMENT_TYPE_MISMATCH,
2513            ErrorCode::ExternalArgumentDefaultMismatch => &EXTERNAL_ARGUMENT_DEFAULT_MISMATCH,
2514            ErrorCode::ExternalOnInterface => &EXTERNAL_ON_INTERFACE,
2515            ErrorCode::MergedDirectiveApplicationOnExternal => {
2516                &MERGED_DIRECTIVE_APPLICATION_ON_EXTERNAL
2517            }
2518            ErrorCode::FieldTypeMismatch => &FIELD_TYPE_MISMATCH,
2519            ErrorCode::FieldArgumentTypeMismatch => &FIELD_ARGUMENT_TYPE_MISMATCH,
2520            ErrorCode::InputFieldDefaultMismatch => &INPUT_FIELD_DEFAULT_MISMATCH,
2521            ErrorCode::FieldArgumentDefaultMismatch => &FIELD_ARGUMENT_DEFAULT_MISMATCH,
2522            ErrorCode::ExternalMissingOnBase => &EXTERNAL_MISSING_ON_BASE,
2523            ErrorCode::InvalidFieldSharing => &INVALID_FIELD_SHARING,
2524            ErrorCode::InvalidShareableUsage => &INVALID_SHAREABLE_USAGE,
2525            ErrorCode::InvalidLinkDirectiveUsage => &INVALID_LINK_DIRECTIVE_USAGE,
2526            ErrorCode::InvalidLinkIdentifier => &INVALID_LINK_IDENTIFIER,
2527            ErrorCode::LinkImportNameMismatch => &LINK_IMPORT_NAME_MISMATCH,
2528            ErrorCode::ReferencedInaccessible => &REFERENCED_INACCESSIBLE,
2529            ErrorCode::DefaultValueUsesInaccessible => &DEFAULT_VALUE_USES_INACCESSIBLE,
2530            ErrorCode::QueryRootTypeInaccessible => &QUERY_ROOT_TYPE_INACCESSIBLE,
2531            ErrorCode::RequiredInaccessible => &REQUIRED_INACCESSIBLE,
2532            ErrorCode::ImplementedByInaccessible => &IMPLEMENTED_BY_INACCESSIBLE,
2533            ErrorCode::DisallowedInaccessible => &DISALLOWED_INACCESSIBLE,
2534            ErrorCode::OnlyInaccessibleChildren => &ONLY_INACCESSIBLE_CHILDREN,
2535            ErrorCode::RequiredInputFieldMissingInSomeSubgraph => {
2536                &REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH
2537            }
2538            ErrorCode::RequiredArgumentMissingInSomeSubgraph => {
2539                &REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH
2540            }
2541            ErrorCode::EmptyMergedInputType => &EMPTY_MERGED_INPUT_TYPE,
2542            ErrorCode::InputFieldMergeFailed => &INPUT_FIELD_MERGE_FAILED,
2543            ErrorCode::EnumValueMismatch => &ENUM_VALUE_MISMATCH,
2544            ErrorCode::EmptyMergedEnumType => &EMPTY_MERGED_ENUM_TYPE,
2545            ErrorCode::ShareableHasMismatchedRuntimeTypes => {
2546                &SHAREABLE_HAS_MISMATCHED_RUNTIME_TYPES
2547            }
2548            ErrorCode::SatisfiabilityError => &SATISFIABILITY_ERROR,
2549            ErrorCode::MaxValidationSubgraphPathsExceeded => {
2550                &MAX_VALIDATION_SUBGRAPH_PATHS_EXCEEDED
2551            }
2552            ErrorCode::OverrideFromSelfError => &OVERRIDE_FROM_SELF_ERROR,
2553            ErrorCode::OverrideSourceHasOverride => &OVERRIDE_SOURCE_HAS_OVERRIDE,
2554            ErrorCode::OverrideCollisionWithAnotherDirective => {
2555                &OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE
2556            }
2557            ErrorCode::OverrideOnInterface => &OVERRIDE_ON_INTERFACE,
2558            ErrorCode::UnsupportedFeature => &UNSUPPORTED_FEATURE,
2559            ErrorCode::InvalidFederationSupergraph => &INVALID_FEDERATION_SUPERGRAPH,
2560            ErrorCode::DownstreamServiceError => &DOWNSTREAM_SERVICE_ERROR,
2561            ErrorCode::DirectiveCompositionError => &DIRECTIVE_COMPOSITION_ERROR,
2562            ErrorCode::InterfaceObjectUsageError => &INTERFACE_OBJECT_USAGE_ERROR,
2563            ErrorCode::InterfaceKeyNotOnImplementation => &INTERFACE_KEY_NOT_ON_IMPLEMENTATION,
2564            ErrorCode::InterfaceKeyMissingImplementationType => {
2565                &INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE
2566            }
2567            ErrorCode::UnsupportedFederationVersion => &UNSUPPORTED_FEDERATION_VERSION,
2568            ErrorCode::UnsupportedFederationDirective => &UNSUPPORTED_FEDERATION_DIRECTIVE,
2569            ErrorCode::QueryPlanComplexityExceededError => &QUERY_PLAN_COMPLEXITY_EXCEEDED,
2570            ErrorCode::NoPlanFoundWithDisabledSubgraphs => &NO_PLAN_FOUND_WITH_DISABLED_SUBGRAPHS,
2571            ErrorCode::CostAppliedToInterfaceField => &COST_APPLIED_TO_INTERFACE_FIELD,
2572            ErrorCode::ListSizeAppliedToNonList => &LIST_SIZE_APPLIED_TO_NON_LIST,
2573            ErrorCode::ListSizeInvalidAssumedSize => &LIST_SIZE_INVALID_ASSUMED_SIZE,
2574            ErrorCode::ListSizeInvalidSlicingArgument => &LIST_SIZE_INVALID_SLICING_ARGUMENT,
2575            ErrorCode::ListSizeInvalidSizedField => &LIST_SIZE_INVALID_SIZED_FIELD,
2576            ErrorCode::ContextNameContainsUnderscore => &CONTEXT_NAME_CONTAINS_UNDERSCORE,
2577            ErrorCode::ContextNameInvalid => &CONTEXT_NAME_INVALID,
2578            ErrorCode::ContextNotSet => &CONTEXT_NOT_SET,
2579            ErrorCode::NoContextReferenced => &NO_CONTEXT_REFERENCED,
2580            ErrorCode::NoSelectionForContext => &NO_SELECTION_FOR_CONTEXT,
2581            ErrorCode::ContextNoResolvableKey => &CONTEXT_NO_RESOLVABLE_KEY,
2582            ErrorCode::ContextSelectionInvalid => &CONTEXT_SELECTION_INVALID,
2583            ErrorCode::InvalidTagName => &INVALID_TAG_NAME,
2584            ErrorCode::ErrorCodeMissing => &ERROR_CODE_MISSING,
2585            ErrorCode::OverrideLabelInvalid => &OVERRIDE_LABEL_INVALID,
2586            ErrorCode::ContextualArgumentNotContextualInAllSubgraphs => {
2587                &CONTEXTUAL_ARGUMENT_NOT_CONTEXTUAL_IN_ALL_SUBGRAPHS
2588            }
2589            ErrorCode::QueryRootMissing => &QUERY_ROOT_MISSING,
2590        }
2591    }
2592}