Bug: FieldResolver metadata leaks into InputType for dual-type classes (shared fields array reference 2.0.0-rc.4)

Author: ScongCreated May 7, 2026Updated Aug 7, 2026
LabelsBug :bug:Community :family_man_girl:

Description

When a class is decorated with both @ObjectType() and @InputType() (a "dual-type" class), field resolvers registered on the objectType side incorrectly appear in the inputType's fields, causing CannotDetermineGraphQLTypeError.

Root Cause

In src/metadata/metadata-storage.ts, the buildClassMetadata method assigns the same array reference from fieldsCache to both the objectType and inputType definitions:

typescript
private buildClassMetadata(definitions: ClassMetadata[]) {
    definitions.forEach(def => {
      if (!def.fields) {
        const fields = this.fieldsCache.get(def.target) || [];
        // ... enriches fields ...
        def.fields = fields;  // <-- shared reference
      }
    });
}

The build() method calls:

typescript
this.buildClassMetadata(this.objectTypes);
this.buildClassMetadata(this.inputTypes);

For a dual-type class, both definitions share the same def.target, so this.fieldsCache.get(def.target) returns the same array. Both definitions end up pointing to the same array instance.

Later, buildFieldResolverMetadata pushes field resolver entries into typeMetadata.fields:

typescript
typeMetadata.fields!.push(fieldMetadata);

Since both objectType and inputType share the same array, the pushed field resolver entry appears in both — causing CannotDetermineGraphQLTypeError when the schema generator processes the inputType (because the field resolver's return type, e.g. a complex object, is not valid as an input type).

Reproduction

typescript
@ObjectType()
@InputType("MyClassInput")
class MyClass {
  @Field()
  id: number;
}

@Resolver(of => MyClass)
class MyClassResolver {
  @FieldResolver(returns => SomeComplexType)
  computed(@Root() root: MyClass) {
    return /* ... */;
  }
}

await buildSchema({ resolvers: [MyClassResolver] });
// Throws: CannotDetermineGraphQLTypeError: Cannot determine GraphQL input type for 'computed' of 'MyClass' class

Suggested Fix

Clone the array on assignment in buildClassMetadata:

diff
-                def.fields = fields;
+                def.fields = [...fields];

This ensures each definition (objectType and inputType) gets its own copy, so mutations to one don't affect the other.

Versions

  • type-graphql: 2.0.0-rc.3 and 2.0.0-rc.4 (bug present in both)
  • graphql: 16.12.0
  • Node.js: 24.x

Workaround

We're using a Yarn patch that applies the one-line fix above to both CJS and ESM builds.

Source: MichalLytek/type-graphql