github/copilot-sdk · error · JsonException

Expected a string token when reading

Error message

Expected a string token when reading {typeToConvert.Name}, but found {reader.TokenType}.

What it means

GeneratedStringEnumJson.ReadValue is the shared JSON reader for string-backed enum/union types. It throws this JsonException when the deserializer hands it a JSON token that is not a string (e.g. a number, object, or array), because the target type can only be constructed from a string value.

Solutions

  1. Fix the JSON payload so the field is a string matching the enum value (e.g. "user" not 1).
  2. Check the API/server for a version change that altered the field's type.
  3. If the value can legitimately be absent, make the property nullable so the converter is not invoked for null tokens.
  4. Catch JsonException during deserialization and log reader position to identify the offending field.

Example fix

// before
var m = JsonSerializer.Deserialize<Message>(json); // json: {"source": 1}
// after
var m = JsonSerializer.Deserialize<Message>("{\"source\": \"user\"}");
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate JSON field type
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.GetProperty("source").ValueKind != JsonValueKind.String)
    throw new ArgumentException("source must be a JSON string");

Type guard

static bool IsStringToken(ref Utf8JsonReader r) => r.TokenType == JsonTokenType.String;

Try / catch

try { var m = JsonSerializer.Deserialize<Message>(json); }
catch (JsonException ex) { log.LogError(ex, "invalid enum token at offset {Offset}", ex.BytesConsumed); }

Prevention

When it happens

Trigger: Deserializing JSON where a field mapped to a GeneratedStringEnumJson-backed type contains a non-string token, e.g. `"role": 1` instead of `"role": "user"`, or the JSON is `null`/an object where a string enum is expected.

Common situations: Hand-written JSON payloads, responses from a server whose schema changed to return numeric or object values, or JSON produced by a different serializer with different type conventions.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/1ff9ccfa64b598f5. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/src/Types.cs:25

using Microsoft.Extensions.Logging;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace GitHub.Copilot;

internal static class GeneratedStringEnumJson
{
    internal static string ReadValue(ref Utf8JsonReader reader, Type typeToConvert)
    {
        if (reader.TokenType != JsonTokenType.String)
        {
            throw new JsonException($"Expected a string token when reading {typeToConvert.Name}, but found {reader.TokenType}.");
        }

        var value = reader.GetString();
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new JsonException($"Expected a non-empty string token when reading {typeToConvert.Name}.");
        }

        return value!;
    }

    internal static void WriteValue(Utf8JsonWriter writer, string value, Type typeToConvert)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new JsonException($"Expected a non-empty string value when writing {typeToConvert.Name}.");
        }

View on GitHub (pinned to cd8cf15dc3)