graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

Optional<T?> produces an "Unable to convert the value of the argument..." error when used in conjunction with mutation conventions

Open kirkbrauer opened this issue 3 years ago • 7 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

When creating a mutation resolver that uses the new mutation conventions feature, using Optional<T?> argument types instead of the base type, results in an Unable to convert the value of the argument... error when executing the mutation.

This only occurs when the input types are automatically generated from the mutation resolver method signature and one or more of those arguments is wrapped in an Optional<> type.

When mutation conventions are disabled and a DTO is created for the input and payload types, the optional values work perfectly and no value conversion errors occur.

Steps to reproduce

  1. Enable mutation conventions for the entire project or a specific mutation resolver method.
  2. Add an Optional<T?> parameter to the method signature.

Here is a repository that demonstrates both the broken mutation conventions and the working DTOs: https://github.com/kirkbrauer/HotChocolateMutationConventionsOptional

Relevant log output

{
  "errors": [
    {
      "message": "Unable to convert the value of the argument `description` to `System.String`. Check if the requested type is correct or register a custom type converter.",
      "locations": [
        {
          "line": 14,
          "column": 3
        }
      ],
      "path": [
        "createBookMutationConvention"
      ],
      "extensions": {
        "fieldName": "createBookMutationConvention",
        "argumentName": "description",
        "requestedType": "System.String"
      }
    }
  ]
}

Additional Context?

Here are the basic resolver implementations for both the working and broken resolvers:

public class Mutation
{
    public Book CreateBookMutationConvention(
        string title,
        Optional<string?> description)
    {
        return new Book
        {
            Id = Guid.NewGuid(),
            Title = title,
            Description = description.HasValue ? description : "No Description"
        };
    }
        
    [UseMutationConvention(Disable = true)]
    public CreateBookPayload CreateBookOld(CreateBookInput input)
    {
        return new CreateBookPayload(new Book
        {
            Id = Guid.NewGuid(),
            Title = input.Title,
            Description = input.Description.HasValue ? input.Description : "No Description"
        });
    }
}

Here are the queries that produce the error using the two types of resolvers:

# Fails with "Unable to convert the value of the argument `description` to `System.String`. Check if the requested type is correct or register a custom type converter."
mutation CreateBookMutationConventionsHasValue {
  createBookMutationConvention(input: { title: "Hello, world", description: "This is a book's description." }) {
    book {
      id
      title
      description
    }
  }
}

# Fails with "Unable to convert the value of the argument `description` to `System.String`. Check if the requested type is correct or register a custom type converter."
mutation CreateBookMutationConventionsNoValue {
  createBookMutationConvention(input: { title: "Hello, world" }) {
    book {
      id
      title
      description
    }
  }
}

# Fails with "Unable to convert the value of the argument `description` to `System.String`. Check if the requested type is correct or register a custom type converter."
mutation CreateBookMutationConventionsNull {
  createBookMutationConvention(input: { title: "Hello, world", description: null }) {
    book {
      id
      title
      description
    }
  }
}

# Works perfectly
mutation CreateBookOld {
  createBookOld(input: {  title: "Hello, world", description: "This is a book's description." }) {
    book {
      id
      title
      description
    }
  }
}

# Works perfectly
mutation CreateBookOldNoValue {
  createBookOld(input: {  title: "Hello, world" }) {
    book {
      id
      title
      description
    }
  }
}

# Works perfectly
mutation CreateBookOldNoValueNull {
  createBookOld(input: {  title: "Hello, world", description: null }) {
    book {
      id
      title
      description
    }
  }
}

Product

Hot Chocolate

Version

12.6.0, 12.7.0-preview.4

kirkbrauer avatar Feb 03 '22 15:02 kirkbrauer

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar May 04 '22 00:05 stale[bot]

So just ignore and let it close? 😒

SiberaIndustries avatar May 11 '22 07:05 SiberaIndustries

@SiberaIndustries no, but we have a lot of stale issues, a comment would have been enough to keep the issue open

PascalSenn avatar May 11 '22 07:05 PascalSenn

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 08 '22 09:09 stale[bot]

+1 to mark this as not stale.

LukeH-Vaiie avatar Mar 06 '23 21:03 LukeH-Vaiie

Still an issue in v13, we can't figure out a way to write a patch mutation due to this. We get this error when following the example code in the docs at https://chillicream.com/docs/hotchocolate/v13/defining-a-schema/input-object-types/#optional-properties

These all result in a crash: [DefaultValue("")] Optional<string?> myString [DefaultValue("")] Optional<string> myString Optional<string?> myString Optional<string> myString

michaelmcneilnet avatar Oct 03 '23 14:10 michaelmcneilnet

Still having this issue (also in the latest prerelease 14.0.0-p.30), however it seems to work when adding the Optional<T?> in a class rather than on the mutation itself.

Working version:


public class Mutations 
{
  [UseMutationConvention]
  public int MutationWorks(Test test)
  {
      return 1;
  }
}

public class Test
{ 
    public Optional<string?> Field { get; set; }
}

Mutation:

mutation ($input: MutationWorksInput!) {
  mutationWorks(input: $input) {
    __typename 
  }
}

Input:

{
  "input": {
    "test": {
      "field": "abc"
    }
  }
}

Of course this creates a weird schema ...

dotTxm avatar Feb 08 '24 08:02 dotTxm

Still having this issue on 13.8.1 - Any news? :)

PKragelund avatar Mar 13 '24 12:03 PKragelund