microsoft/semantic-kernel · info · InvalidOperationException
Audio content URI is empty.
Error message
Audio content URI is empty.
What it means
Thrown by CreateGeminiPartFromAudio when building a Gemini FileDataPart for an AudioContent that has a URI. The expression audioContent.Uri ?? throw guards against a null URI. In practice this throw is unreachable because it sits inside an 'if (audioContent.Uri is not null)' block, so the value was just proven non-null; it is defensive code to satisfy nullable reference analysis and protect against concurrent mutation of the content object.
Source
Thrown at dotnet/src/Connectors/Connectors.Google/Core/Gemini/Models/GeminiRequest.cs:375
{
return new GeminiPart
{
InlineData = new GeminiPart.InlineDataPart
{
MimeType = GetMimeTypeFromAudioContent(audioContent),
InlineData = Convert.ToBase64String(audioContent.Data.Value.ToArray())
}
};
}
if (audioContent.Uri is not null)
{
return new GeminiPart
{
FileData = new GeminiPart.FileDataPart
{
MimeType = GetMimeTypeFromAudioContent(audioContent),
FileUri = audioContent.Uri ?? throw new InvalidOperationException("Audio content URI is empty.")
}
};
}
throw new InvalidOperationException("Audio content does not contain any data or uri.");
}
private static string GetMimeTypeFromAudioContent(AudioContent audioContent)
{
return audioContent.MimeType
?? throw new InvalidOperationException("Audio content MimeType is empty.");
}
private static GeminiPart CreateGeminiPartFromBinary(BinaryContent binaryContent)
{
// Binary data takes precedence over URI.
if (binaryContent.Data is { IsEmpty: false })
{View on GitHub (pinned to c028a0c7dc)
Solutions
- Do not mutate an AudioContent instance concurrently with serializing it; treat content objects as effectively immutable once handed to the kernel.
- If you are seeing this in production, audit for code that reuses/clears the same AudioContent across parallel requests.
- Supply a copy of the content or a freshly constructed AudioContent per request.
Example fix
// before (shared mutable content) var audio = new AudioContent(...); // task A: kernel.InvokeAsync(... audio ...) // serializes // task B: audio.Uri = null; // mutates during serialize // after (one immutable content per request) var audio = new AudioContent(uri: myUri, mimeType: "audio/wav"); await kernel.InvokeAsync(... audio ...);
Defensive patterns
Strategy: validation
Validate before calling
// Validate AudioContent immutability before invoking
static bool IsAudioContentSafe(AudioContent c)
=> c.Uri is not null && !string.IsNullOrEmpty(c.MimeType);
// Then ensure no concurrent mutation of c.Uri occurs during the call. Prevention
- Treat AudioContent (and all content objects) as immutable once passed to the kernel.
- Never share a content instance across parallel invocations that mutate it.
- Construct a fresh AudioContent per request rather than reusing/clearing one.
When it happens
Trigger: Only fires if audioContent.Uri is reassigned to null between the 'is not null' check (line 368) and the FileUri assignment (line 375) — i.e. a race condition where another thread mutates the same AudioContent instance during request serialization.
Common situations: Sharing a single AudioContent instance across threads/tasks while one thread serializes a Gemini request and another clears or replaces the Uri. Effectively never hit in single-threaded usage.
Related errors
- Binary content URI is empty.
- Audio content does not contain any data or uri.
- Audio content MimeType is empty.
- Runtime is already stopping.
- Failed to parse the provided audio options from JSON. Ensure
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/bc8d65008ebfe486.
Report an issue: GitHub.