microsoft/semantic-kernel · error · ArgumentException

Unknown image detail level '{detailLevelString}'. Supported

Error message

Unknown image detail level '{detailLevelString}'. Supported values are 'Auto', 'Low' and 'High'.

What it means

Thrown by GetChatImageDetailLevel when an image's metadata carries a 'ChatImageDetailLevel' string that is not Auto/Low/High (case-insensitive). The detail level controls OpenAI's vision processing budget; an unknown token cannot be sent, so an ArgumentException lists the valid values.

Source

Thrown at dotnet/src/Connectors/Connectors.OpenAI/Core/ClientCore.ChatCompletion.cs:955

        };
    }

    private static ChatImageDetailLevel? GetChatImageDetailLevel(ImageContent imageContent)
    {
        const string DetailLevelProperty = "ChatImageDetailLevel";

        if (imageContent.Metadata is not null &&
            imageContent.Metadata.TryGetValue(DetailLevelProperty, out object? detailLevel) &&
            detailLevel is not null)
        {
            if (detailLevel is string detailLevelString && !string.IsNullOrWhiteSpace(detailLevelString))
            {
                return detailLevelString.ToUpperInvariant() switch
                {
                    "AUTO" => ChatImageDetailLevel.Auto,
                    "LOW" => ChatImageDetailLevel.Low,
                    "HIGH" => ChatImageDetailLevel.High,
                    _ => throw new ArgumentException($"Unknown image detail level '{detailLevelString}'. Supported values are 'Auto', 'Low' and 'High'.")
                };
            }
        }

        return null;
    }

    private OpenAIChatMessageContent CreateChatMessageContent(OAIChat.ChatCompletion completion, string targetModel, bool retainArgumentTypes, OAIChat.ChatCompletionOptions options)
    {
        var message = new OpenAIChatMessageContent(completion, targetModel, this.GetChatCompletionMetadata(completion));

        if (completion.OutputAudio is ChatOutputAudio outputAudio)
        {
            var audioContent = new AudioContent(outputAudio.AudioBytes, GetAudioOutputMimeType(options.AudioOptions))
            {
                Metadata = new Dictionary<string, object?>
                {
                    [nameof(outputAudio.Id)] = outputAudio.Id,

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Use only 'Auto', 'Low', or 'High' for the ChatImageDetailLevel metadata string.
  2. Omit the metadata key entirely if you want the default (the method returns null and OpenAI picks a default).
  3. If storing the enum, use the ChatImageDetailLevel enum instead of a free string.

Example fix

// before
image.Metadata["ChatImageDetailLevel"] = "full";
// after
image.Metadata["ChatImageDetailLevel"] = "High";
Defensive patterns

Strategy: validation

Validate before calling

static readonly HashSet<string> ValidDetail = new(StringComparer.OrdinalIgnoreCase) { "auto","low","high" };
static void SetImageDetail(ImageContent img, string? d) { if (d is null) return; if (!ValidDetail.Contains(d)) throw new ArgumentException($"Detail must be Auto/Low/High"); img.Metadata["ChatImageDetailLevel"] = d.ToLowerInvariant(); }

Type guard

static bool IsValidImageDetail(string? d) => d is null || ValidDetail.Contains(d);

Try / catch

try { await client.GetChatCompletionAsync(history); }
catch (ArgumentException ex) when (ex.Message.Contains("detail level")) { /* remove metadata key and retry */ }

Prevention

When it happens

Trigger: Setting imageContent.Metadata["ChatImageDetailLevel"] to a string like 'none', 'full', 'max', or a numeric value, then sending the image.

Common situations: Confusing this with the (separate) enum form; passing a value from another vision API; copy-pasting an unsupported token.

Related errors


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