Skip to content

[GraphQL] Custom Query args: referencing another resource's derived enum type crashes schema build ("The type ... was not resolved") #8473

Description

@brunobg

API Platform version(s) affected: 4.3.17 (also reproduces on 4.3.4)

Description

A custom #[GraphQl\Query]'s args: entry that names a GraphQL enum type by string — one that only exists in the schema because another resource has a property typed with that backed enum — crashes the entire schema build with:

The type "WidgetStatus!" was not resolved.

thrown from TypeConverter::resolveType(). The root cause: typesContainer only gets WidgetStatus registered as a side effect of building Widget's own GraphQL fields, which has not necessarily happened yet when FieldsBuilder::resolveResourceArgs() eagerly resolves this custom query's arg type. Because schema build is a single pass over the whole Query type, this takes down every /graphql request, not just the one query that declared the bad arg — there is no partial-schema fallback.

This looks like the same root cause as #8068 ("Type ... is not present in the types container", nested mutation input, still open) and #3651 (a custom ObjectType referencing an entity type too early, closed wontfix) — different trigger, same underlying typesContainer-populated-lazily-and-incompletely problem.

How to reproduce

Minimal Symfony 7 + api-platform/symfony + api-platform/graphql project, no Doctrine, no database. Two plain resources:

src/Enum/WidgetStatus.php:

enum WidgetStatus: string
{
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
}

src/ApiResource/Widget.php — property typed with the enum, which is what registers the WidgetStatus GraphQL type:

#[ApiResource(
    operations: [],
    graphQlOperations: [new Query(resolver: WidgetQueryResolver::class)],
)]
final class Widget
{
    #[ApiProperty(identifier: true)]
    public string $id = '1';

    public WidgetStatus $status = WidgetStatus::DRAFT;
}

src/ApiResource/WidgetStatusOptions.php — an unrelated resource whose custom query's arg names that enum:

#[ApiResource(
    operations: [],
    graphQlOperations: [
        new Query(
            name: 'widgetStatusOptions',
            resolver: WidgetStatusOptionsQueryResolver::class,
            args: ['status' => ['type' => 'WidgetStatus!']],
            read: false,
        ),
    ],
)]
final class WidgetStatusOptions
{
    #[ApiProperty(identifier: true)]
    public string $id = '1';

    /** @var list<string> */
    public array $allowedNext = [];
}

(Resolvers just return new Widget() / new WidgetStatusOptions() — happy to push the full minimal project to a repo on request.)

Running bin/console api:graphql:export (or hitting /api/graphql) throws immediately:

In TypeConverter.php line 134:
  [ApiPlatform\Metadata\Exception\InvalidArgumentException]
  The type "WidgetStatus!" was not resolved.

Exception trace:
 TypeConverter->resolveType() at vendor/api-platform/graphql/Type/TypeConverter.php:134
 FieldsBuilder->resolveResourceArgs() at vendor/api-platform/graphql/Type/FieldsBuilder.php:307
 FieldsBuilder->getItemQueryFields() at vendor/api-platform/graphql/Type/FieldsBuilder.php:91
 SchemaBuilder->getSchema() at vendor/api-platform/graphql/Type/SchemaBuilder.php:63
 GraphQlExportCommand->execute() at vendor/api-platform/symfony/Bundle/Command/GraphQlExportCommand.php:69

Possible Solution

Either resolve the type regardless of resource-processing order (e.g. force-build every resource's fields, or at least every resource that contributes a type referenced from args:, before resolving custom-query arg types), or fail at attribute-declaration time with a clear message saying a custom query's args: cannot reference a resource-derived type — rather than crashing the whole schema at request time with a message that doesn't say why the type wasn't found.

Workaround we're using in the meantime: declare the arg as 'type' => 'String!' and match the incoming value against WidgetStatus::cases() by hand inside the resolver. This is presumably why every other custom-query-with-a-typed-arg example in the docs/tests only uses String/Int/Float.

Additional Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions