dotnet/machinelearning · error · InvalidOperationException
Please provide a message with content.
Error message
Please provide a message with content.
What it means
Phi3ChatTemplateBuilder.BuildPrompt(IEnumerable<IMessage>) validates that every message has non-null content before rendering the Phi-3 chat template. Any message whose GetContent() is null makes the prompt impossible to render, so it throws InvalidOperationException.
Source
Thrown at src/Microsoft.ML.GenAI.Phi/Phi3/Phi3ChatTemplateBuilder.cs:30
using Microsoft.ML.GenAI.Core;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using TextContent = Microsoft.SemanticKernel.TextContent;
namespace Microsoft.ML.GenAI.Phi;
public class Phi3ChatTemplateBuilder : IChatTemplateBuilder, IMEAIChatTemplateBuilder
{
private const char Newline = '\n';
public static Phi3ChatTemplateBuilder Instance { get; } = new Phi3ChatTemplateBuilder();
public string BuildPrompt(IEnumerable<IMessage> messages, IEnumerable<FunctionContract>? tools = null)
{
var availableRoles = new[] { Role.System, Role.User, Role.Assistant };
if (messages.Any(m => m.GetContent() is null))
{
throw new InvalidOperationException("Please provide a message with content.");
}
if (messages.Any(m => m.GetRole() is null || availableRoles.Contains(m.GetRole()!.Value) == false))
{
throw new InvalidOperationException("Please provide a message with a valid role. The valid roles are System, User, and Assistant.");
}
// construct template based on instruction from
// https://huggingface.co/microsoft/Phi-3-mini-128k-instruct#chat-format
var sb = new StringBuilder();
foreach (var message in messages)
{
var role = message.GetRole()!.Value;
var content = message.GetContent()!;
sb.Append(message switch
{
_ when message.GetRole() == Role.System => $"<|system|>{Newline}{content}<|end|>{Newline}",View on GitHub (pinned to 7b76e69cf9)
Solutions
- Filter out messages with null content before calling BuildPrompt.
- Replace null-content messages with a placeholder string such as string.Empty or '[no content]'.
- Fix upstream message construction/deserialization so Content is always populated.
Example fix
// before var prompt = builder.BuildPrompt(messages); // after var prompt = builder.BuildPrompt(messages.Where(m => m.GetContent() is not null));
Defensive patterns
Strategy: validation
Validate before calling
bool allHaveContent = messages.All(m => m.GetContent() is not null);
if (!allHaveContent) throw new InvalidOperationException("All messages must have content before building the Phi-3 prompt."); Type guard
bool HasContent(IMessage m) => m.GetContent() is not null;
Try / catch
try { var prompt = builder.BuildPrompt(messages); } catch (InvalidOperationException ex) when (ex.Message.Contains("message with content")) { messages = messages.Where(m => m.GetContent() is not null); prompt = builder.BuildPrompt(messages); } Prevention
- Validate chat history at ingestion time, not at template-build time.
- Never construct TextMessage with a null body — use string.Empty if needed.
- Sanitize deserialized messages before adding them to history.
When it happens
Trigger: Passing a message collection to BuildPrompt where at least one IMessage has null content — e.g. a message constructed from a null string, a tool-call-only message, or deserialization that left Content unset.
Common situations: Binding chat history from external JSON where 'content' was absent; creating TextMessage with a null body programmatically; including function-call result messages that carry no textual content.
Related errors
- Please provide a message with a valid role. The valid roles
- Invalid role.
- Only text content is supported, but got {item.GetType().Name
- Unsupported role {message.Role}
- {nameof(numberOfCVFolds)} must be at least 2
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/5ca1ec248d0e8e74.
Report an issue: GitHub.