diff --git a/src/HotChocolate/Fusion/src/Fusion.Composition/PostMergeValidationRules/ImplementedByInaccessibleRule.cs b/src/HotChocolate/Fusion/src/Fusion.Composition/PostMergeValidationRules/ImplementedByInaccessibleRule.cs index 33c7ace5853..df49a281b20 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Composition/PostMergeValidationRules/ImplementedByInaccessibleRule.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Composition/PostMergeValidationRules/ImplementedByInaccessibleRule.cs @@ -52,7 +52,14 @@ private static void Handle( foreach (var interfaceField in accessibleInterfaceFields) { - var field = type.Fields[interfaceField.Name]; + // An implementing type can be missing fields that were contributed to a merged + // interface by another source schema. That missing-field case is validated + // separately (e.g. by InterfaceFieldNoImplementationRule for object types), so we + // skip it here to avoid throwing when looking up the field on the implementing type. + if (!type.Fields.TryGetField(interfaceField.Name, out var field)) + { + continue; + } if (field.HasFusionInaccessibleDirective() || type.HasFusionInaccessibleDirective()) diff --git a/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/PostMergeValidationRules/ImplementedByInaccessibleRuleTests.cs b/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/PostMergeValidationRules/ImplementedByInaccessibleRuleTests.cs index 95e267cc6d2..6a5c59a934a 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/PostMergeValidationRules/ImplementedByInaccessibleRuleTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/PostMergeValidationRules/ImplementedByInaccessibleRuleTests.cs @@ -150,4 +150,34 @@ interface User implements Node { """ ]); } + + // When two source schemas declare the same-named interface with different fields, the merged + // interface holds the union of those fields, so an implementing type does not necessarily + // provide every field of the interface. This rule must not assume the field exists on the + // implementing type; the unimplemented field is reported by InterfaceFieldNoImplementationRule. + [Fact] + public void Validate_MergedInterfaceFieldNotOnAllImplementers_Succeeds() + { + AssertValid( + [ + """ + interface Error { + code: String! + } + + type ErrorWithCode implements Error { + code: String! + } + """, + """ + interface Error { + message: String! + } + + type ErrorWithMessage implements Error { + message: String! + } + """ + ]); + } }