microsoft/semantic-kernel · error · JsonException

Unexpected author role: {role}

Error message

Unexpected author role: {role}

What it means

Thrown by AuthorRoleConverter.Read (the JSON deserialization path) when the 'role' string in a Gemini response does not match 'user', 'model', or 'function' (case-insensitive comparison). Gemini's API uses these three role strings; anything else cannot be mapped to an SK AuthorRole.

Source

Thrown at dotnet/src/Connectors/Connectors.Google/Core/Gemini/AuthorRoleConverter.cs:35

            return null;
        }

        if (role.Equals("user", StringComparison.OrdinalIgnoreCase))
        {
            return AuthorRole.User;
        }

        if (role.Equals("model", StringComparison.OrdinalIgnoreCase))
        {
            return AuthorRole.Assistant;
        }

        if (role.Equals("function", StringComparison.OrdinalIgnoreCase))
        {
            return AuthorRole.Tool;
        }

        throw new JsonException($"Unexpected author role: {role}");
    }

    public override void Write(Utf8JsonWriter writer, AuthorRole? value, JsonSerializerOptions options)
    {
        if (value is null)
        {
            writer.WriteNullValue();
            return;
        }

        if (value == AuthorRole.Tool)
        {
            writer.WriteStringValue("function");
        }
        else if (value == AuthorRole.Assistant)
        {
            writer.WriteStringValue("model");
        }

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Upgrade the Connectors.Google package if Google introduced a new role the connector should support.
  2. If using a mock or proxy, ensure role strings are exactly 'user', 'model', or 'function'.
  3. Catch JsonException when processing Gemini responses to gracefully handle unrecognized roles.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

static bool IsValidGeminiRole(string role) =>
    role.Equals("user", StringComparison.OrdinalIgnoreCase) ||
    role.Equals("model", StringComparison.OrdinalIgnoreCase) ||
    role.Equals("function", StringComparison.OrdinalIgnoreCase);

Try / catch

try
{
    var response = await client.GetChatMessageContentAsync(history, settings, ct);
}
catch (JsonException ex) when (ex.Message.Contains("Unexpected author role"))
{
    logger.LogError(ex, "Gemini returned an unrecognized author role. " +
        "This may indicate an API version mismatch.");
    throw;
}

Prevention

When it happens

Trigger: The Gemini API returns a response containing a role string that is not 'user', 'model', or 'function'. This fires during JSON deserialization of chat completion or streaming responses. Case does not matter (OrdinalIgnoreCase), but the literal string must match.

Common situations: Google introduces a new role string in a future API version (e.g. 'system' or 'developer'). A proxy or mock server returns responses with incorrect role values. The API returns an error response that partially deserializes as a valid structure but with unexpected field values.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/e99b8f50d106b4e2. Report an issue: GitHub.