microsoft/semantic-kernel · error · InvalidOperationException

Unable to transform result into {typeof(TOutput).Name}

Error message

Unable to transform result into {typeof(TOutput).Name}

What it means

StructuredOutputTransform<TOutput>.TransformAsync calls a chat completion service, then does JsonSerializer.Deserialize<TOutput> on response.Content. If deserialization returns null (e.g. content is empty, "null", or non-JSON) it throws InvalidOperationException. Unlike the default transform, a JsonException from invalid JSON is NOT caught here — it propagates as a JsonException, while a successful parse to null hits this throw.

Source

Thrown at dotnet/src/Agents/Orchestration/Transforms/StructuredOutputTransform.cs:59

    /// <summary>
    /// Transforms the provided <see cref="ChatMessageContent"/> into a strongly-typed structured output by invoking the chat completion service and deserializing the response.
    /// </summary>
    /// <param name="messages">The chat messages to process.</param>
    /// <param name="cancellationToken">A cancellation token to observe while waiting for the task to complete.</param>
    /// <returns>The structured output of type <typeparamref name="TOutput"/>.</returns>
    /// <exception cref="InvalidOperationException">Thrown if the response cannot be deserialized into <typeparamref name="TOutput"/>.</exception>
    public async ValueTask<TOutput> TransformAsync(IList<ChatMessageContent> messages, CancellationToken cancellationToken = default)
    {
        ChatHistory history =
            [
                new ChatMessageContent(AuthorRole.System, this.Instructions),
                .. messages,
            ];
        ChatMessageContent response = await this._service.GetChatMessageContentAsync(history, this._executionSettings, kernel: null, cancellationToken).ConfigureAwait(false);
        return
            JsonSerializer.Deserialize<TOutput>(response.Content ?? string.Empty) ??
            throw new InvalidOperationException($"Unable to transform result into {typeof(TOutput).Name}");
    }
}

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Configure PromptExecutionSettings to enforce JSON output (e.g. response_format = json_object) if the connector supports it.
  2. Strengthen the Instructions to forbid null/empty and require the target schema.
  3. If the model cannot reliably produce JSON, switch to a stronger model or use the default transform with a JSON-emitting agent.

Example fix

// before
var transform = new StructuredOutputTransform<Summary>(chat, new PromptExecutionSettings());

// after
var settings = new PromptExecutionSettings { ExtensionData = new Dictionary<string, object> { ["response_format"] = new { type = "json_object" } } };
var transform = new StructuredOutputTransform<Summary>(chat, settings) { Instructions = "Respond ONLY with JSON matching the Summary schema. Never return null." };
Defensive patterns

Strategy: try-catch

Try / catch

TOutput parsed;
try { parsed = await transform.TransformAsync(messages, ct); }
catch (InvalidOperationException ex)
{
    // model returned null/empty JSON; retry with stricter instructions or fail soft
    throw new InvalidOperationException("Model did not return valid JSON for " + typeof(TOutput).Name, ex);
}

Prevention

When it happens

Trigger: The model returns an empty string (response.Content ?? string.Empty yields ""), returns the literal token `null`, or returns JSON whose root value is null; the model ignores the JSON instruction and returns prose that happens to parse to null.

Common situations: Execution settings lacking a JSON response-format constraint; using a model that does not reliably follow JSON instructions; empty/blank completion from a rate-limited or misconfigured endpoint; Instructions left at the default and the model returning null for nullable TOutput.

Related errors


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