Cannot get the value of a token type ‘StartObject’/converter ‘…’ read too much or not enough

This blog post describes two exceptions that I experienced while converting Newtonsoft JsonConverters to System.Text.Json JsonConverters and the related solutions to both issues in the hopes that it may assist developers that may face the same issue(s).

Update 1.June.2021: This is a bit embarrassing, but I eventually remembered/realized that the CMS models a Reference field to support multiple values even if I define the field to allow only one reference. I modeled the reference field as a single value, so the Read() statements were skipping the JSON [ and ] array enclosure characters around the list of references and populating my single value from the one element in that array, which became a problem when I tried to model a reference field that did allow multiple references. What I needed to do was model both reference fields as list properties and accessed the first element and not use the code below. Anyway, maybe this post still has some useful information for someone with similar issues. See also:

Original post:

Here are the relevant bits of the first exception that I received.

InvalidOperationException: Cannot get the value of a token type 'StartObject' as a string.
System.Text.Json.Utf8JsonReader.GetString()
JsonException: The JSON value could not be converted 
...
System.Text.Json.Serialization.JsonConverter<T>.ReadCore(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state)

Here are the relevant bits of the section exception that I received. The last bits about entryModel and json.GetRawText() are from my code.

JsonException: The converter '...' read too much or not enough. Path: ... LineNumber ... BytePositionInLine ...
System.Text.Json.ThrowHelper.ThrowJsonException_SerializationConverterRead(JsonConverter converter)
...
object entryModel = JsonSerializer.Deserialize(json.GetRawText(),

In the first case, I was missing a reader.Read() method call that must advance the parser past a token in the JSON.

In the second case, I was missing a reder.Read() method call that must advance the parser past the closing of that token in the JSON.

public override TBlockBase Read(
    ref Utf8JsonReader reader, 
    Type typeToConvert, 
    JsonSerializerOptions options)
{
    // Move from the StartObject token to the first element,
    // which identifies the type of the modular block
    reader.Read();

    // block type
    TBlockTypeEnum parsed;

    if (Enum.TryParse(
        reader.GetString(),
        true,
        out parsed))
    {
        foreach (Type t in Assembly.GetAssembly(
            typeof(TBlockBase)).GetTypes().Where(
                myType => myType.IsClass
                    && !myType.IsAbstract
                    && myType.IsSubclassOf(typeof(TBlockBase))))
        {
            TBlockBase obj = (TBlockBase)Activator.CreateInstance(t);

            foreach (PropertyInfo propertyInfo
                in obj.GetType().GetRuntimeProperties())
            {
                if (propertyInfo.PropertyType == typeof(TBlockTypeEnum))
                {
                    if (((int)propertyInfo.GetValue(obj))
                        == parsed.ToInt32(CultureInfo.InvariantCulture))
                    {
                        TBlockBase result = (TBlockBase)JsonSerializer.Deserialize(
                            ref reader, obj.GetType(), options);

                        // move parser past the closing of the StartObject
                        reader.Read();

                        return result;
                    }
                }
            }
        }
    }

    Trace.Assert(
        false,
        "Unable to locate " + typeof(TBlockTypeEnum) + " property or matching "
        + parsed + " in classes of " + Assembly.GetAssembly(typeof(TBlockBase))
        + " that derive from " + typeof(TBlockBase));
    return null;
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: