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
- Fix the JSON payload so the field is a string matching the enum value (e.g. "user" not 1).
- Check the API/server for a version change that altered the field's type.
- If the value can legitimately be absent, make the property nullable so the converter is not invoked for null tokens.
- 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
- Always emit enum fields as JSON strings
- Contract-test payloads against the SDK schema
- Pin server/client schema versions together
- Validate payloads with a JSON schema before deserializing
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
- Failed to deserialize permission request
- Expected a non-empty string token when reading
- Expected string for ToolBinaryResultType.
- ToolBinaryResultType value cannot be null.
- Unknown MessageSource value
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)