OrchardCMS/OrchardCore · error · JsonException

Unknown token type

Error message

Unknown token type {0}

What it means

This is the terminal fallback of DynamicJsonConverter.Read: after the switch exhausts all recognized JsonTokenType cases it throws a JsonException formatted with the unknown reader.TokenType. Unlike error 45 (thrown inside object parsing), this fires at the top-level dispatch, meaning the very first/most recent token read was of a type the converter never mapped at all. It signals the converter was handed JSON it was never designed to consume.

Solutions

  1. Check reader.TokenType before calling the deserializer; call reader.Read() at least once so TokenType is not None.
  2. Strip comments or avoid JsonCommentHandling.Allow when the payload goes through this converter.
  3. Ensure the stream/reader is rewound (reader = new Utf8JsonReader(buffer)) and not already exhausted before deserialization.
  4. Deserialize the complete top-level value (object/array), not a fragment; wrap primitives in a document if needed.
  5. If a new token type is valid for your data, add an explicit case for it in DynamicJsonConverter.Read.

Example fix

// before: unadvanced reader
var reader = new Utf8JsonReader(buffer);
var value = JsonSerializer.Deserialize<JsonDynamicObject>(ref reader);

// after: advance the reader to a real token first
var reader = new Utf8JsonReader(buffer);
if (!reader.Read()) throw new InvalidDataException("Empty payload");
if (reader.TokenType == JsonTokenType.StartObject)
{
    var value = JsonSerializer.Deserialize<JsonDynamicObject>(ref reader);
}
Defensive patterns

Strategy: validation

Validate before calling

var reader = new Utf8JsonReader(buffer);
if (!reader.Read()) throw new InvalidDataException("Empty JSON payload");
if (reader.TokenType is JsonTokenType.None or JsonTokenType.Comment or JsonTokenType.PropertyName or JsonTokenType.EndObject or JsonTokenType.EndArray)
    throw new InvalidDataException($"Reader must start on a value token, got {reader.TokenType}");

Type guard

static bool IsValueStartToken(JsonTokenType t) =>
    t is JsonTokenType.StartObject or JsonTokenType.StartArray
        or JsonTokenType.String or JsonTokenType.Number
        or JsonTokenType.True or JsonTokenType.False or JsonTokenType.Null;

Try / catch

try
{
    var value = JsonSerializer.Deserialize<JsonDynamicObject>(ref reader, options);
}
catch (JsonException ex) when (ex.Message.StartsWith("Unknown token type"))
{
    logger.LogError(ex, "Reader was on token {Token}; rewind the reader to a value start", reader.TokenType);
    reader = new Utf8JsonReader(buffer); reader.Read(); // rewind and retry once
}

Prevention

When it happens

Trigger: JsonSerializer.Deserialize/Serialize with a type routed through DynamicJsonConverter when reader.TokenType is outside the handled set — e.g. None (reader not advanced), a stray PropertyName, EndObject/EndArray reached as a value position, or a comment token (JsonCommentHandling.Allow).

Common situations: Passing an unadvanced Utf8JsonReader (TokenType == None) into deserialization; enabling comment handling and feeding JSON with comments; calling Deserialize on a stream already consumed; custom pipeline code that re-reads a value and hands the converter an EndObject token.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/d5562863079c15d7. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore.Abstractions/Json/Serialization/DynamicJsonConverter.cs:93

                        case JsonTokenType.PropertyName:
                            var key = reader.GetString();
                            reader.Read();
                            if (key is not null)
                            {
                                dictionary[key] = Read(ref reader, typeof(object), options);
                            }

                            break;

                        default:
                            throw new JsonException("Cannot parse object.");
                    }
                }

                throw new JsonException();

            default:
                throw new JsonException(string.Format("Unknown token type {0}", reader.TokenType));
        }
    }

    public override void Write(
        Utf8JsonWriter writer,
        object objectToWrite,
        JsonSerializerOptions options) =>
        JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
}

View on GitHub (pinned to 4306c0717f)