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

  1. Do not mutate an AudioContent instance concurrently with serializing it; treat content objects as effectively immutable once handed to the kernel.
  2. If you are seeing this in production, audit for code that reuses/clears the same AudioContent across parallel requests.
  3. 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

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


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