reactiveui/refit · error · JsonException

Unexpected token when parsing .

Error message

Unexpected token {reader.TokenType} when parsing {typeof(TEnum)}.

What it means

Thrown by CamelCaseStringEnumConverter.ReadValue when the current JSON token is neither a string/property-name nor a number — e.g. true/false, null, start of object/array. The converter only knows how to map strings (names) and numbers (underlying values) to enum fields, so any other token type is an error.

Solutions

  1. Correct the JSON to send a valid enum name (string) or numeric value for the field.
  2. If the field can legitimately be absent, make the property a nullable enum (MyEnum?) so null is tolerated by the nullable converter.
  3. If the source genuinely sends a non-string/number, change the receiving type (e.g. bool) or pre-transform the JSON.

Example fix

// before — non-nullable enum receives a boolean token
public sealed record Payload(Status Status);
// JSON: { "status": true }  -> throws Unexpected token True

// after — correct the payload type, or make nullable if absent is valid
public sealed record Payload(Status? Status);
// and send { "status": "active" } or { "status": 1 }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the JSON token type for enum fields before deserializing.
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("status", out var el)
    && el.ValueKind is not (JsonValueKind.String or JsonValueKind.Number))
{
    throw new InvalidDataException("status must be a string or number.");
}

Try / catch

try { return JsonSerializer.Deserialize<Payload>(json); }
catch (JsonException ex) when (ex.Message.Contains("Unexpected token"))
{ /* wrong token type for enum — fix payload or DTO type */ }

Prevention

When it happens

Trigger: The JSON for an enum field is a boolean, null, object, or array rather than a string or number, e.g. `{ "status": true }` or `{ "status": null }` (for a non-nullable enum) or `{ "status": {} }`.

Common situations: Server changes a field's type (e.g. from a string code to a boolean flag); a non-nullable enum receiving JSON null; malformed/inconsistent payloads; schema drift after an API change.

Understand the failure class

Related errors


AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13). Data as JSON: /api/errors/4f72618895fb23f6. Report an issue: GitHub.

Appendix: source

Thrown at src/Refit/CamelCaseStringEnumConverter.cs:229

                if (_namesToValues.TryGetValue(value!, out var namedValue))
                {
                    return namedValue;
                }

                if (_namesToValuesIgnoreCase.TryGetValue(value!, out var namedValueIgnoreCase))
                {
                    return namedValueIgnoreCase;
                }

                throw new JsonException($"Unable to convert '{value}' to {typeof(TEnum)}.");
            }

            if (reader.TokenType == JsonTokenType.Number)
            {
                return EnumHelpers.Info<TEnum>.ReadJsonNumericValue(ref reader);
            }

            throw new JsonException($"Unexpected token {reader.TokenType} when parsing {typeof(TEnum)}.");
        }
    }

    /// <summary>A strongly-typed JSON converter for nullable enums that maps values to and from camelCase names.</summary>
    /// <typeparam name="TEnum">The underlying enum type.</typeparam>
    internal sealed class NullableEnumConverter<
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum> : JsonConverter<TEnum?>
        where TEnum : struct, Enum
    {
        /// <summary>The underlying non-nullable enum converter that performs the name/value mapping.</summary>
        private readonly EnumConverter<TEnum> _inner = new();

        /// <inheritdoc/>
        public override TEnum? Read(
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options) =>
            IsNullOrEmptyString(ref reader) ? null : _inner.Read(ref reader, typeof(TEnum), options);

View on GitHub (pinned to b455f65ecc)