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