You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Fragment on an interface that spreads a fragment on a parent interface drops the inheritance edge and the parent's fields from the base class #415
When a fragment defined on interface A spreads a fragment defined on a super-interfaceB (schema: A implements B), the generated base class Fragment$AFragment:
does notimplements Fragment$BFragment, and
does not carry B's fields.
The interface relationship and B's fields appear only on the per-possible-type variant classes Fragment$AFragment$$ConcreteType. So a value statically typed as the base A fragment can be neither upcast to B nor read for B's fields. You're forced to switch on __typename/a type enum and downcast to a concrete leaf by hand.
class Fragment$AnimalFragment implements Fragment$NodeFragment
Fragment$AnimalFragment exposes both id (from NodeFragment) and name.
Actual
class Fragment$AnimalFragment { … } implements nothing.
It exposes only name + $__typename; id exists only on Fragment$AnimalFragment$$Dog.
To read id from an AnimalFragment, you must is/cast to the $$Dog variant.
Root cause (located)
In lib/src/visitor/context_visitor.dart, visitFragmentSpreadNode returns early for any spread whose type condition isn't an exact match once the current type is abstract:
if (context.currentType is!ObjectTypeDefinitionNode) {
return; // ← abstract current type + super-interface spread → dropped entirely
}
The exact-match branch above it (_visitInFragment(...), which records both the fields and the implements edge via addFragment(...)) is what makes inheritance work, but it's skipped here, so super-interface spreads into an abstract fragment contribute nothing to the base context. The relationship survives only on the concrete $$ConcreteType variants built by _buildConcreteTypeContexts.
Environment
graphql_codegen 3.0.1, graphql 5.1.3, Dart 3.x.
Note for maintainers
A naive fix (hoist the fields + add the implements edge for the subsumes case) collides with the per-interface maybeWhen API: Fragment$AnimalFragment.maybeWhen takes Animal$$Dog callbacks while Fragment$NodeFragment.maybeWhen takes Node$$Dog callbacks, and since Animal$$Dog <: Node$$Dog, the sub-interface's maybeWhen would be a non-contravariant (illegal) override. So a complete fix also has to change where maybeWhen is emitted (e.g. emit it only on the root abstract type, or move discrimination to native is/switch over the variant lattice).
👋 @behnamsattar
Thank you for raising an issue. I will investigate the issue and get back to you as soon as possible.
Please make sure you have provided enough context.
This library is created and maintained by me, @budde377. Please consider supporting my work and ensure our survival by donating here.
Activity
github-actions commentedon Jun 21, 2026
👋 @behnamsattar
Thank you for raising an issue. I will investigate the issue and get back to you as soon as possible.
Please make sure you have provided enough context.
This library is created and maintained by me, @budde377. Please consider supporting my work and ensure our survival by donating here.
budde377 commentedon Jul 5, 2026
Thanks for reporting this. Check v3.0.2 and see how it works for you.
behnamsattar commentedon Jul 6, 2026
@budde377 it worked very well, and addressed the issue I had. Thanks!