iOfficeAI/OfficeCLI · error · ArgumentException

Invalid data URI: empty base64 payload (would produce a 0-by

Error message

Invalid data URI: empty base64 payload (would produce a 0-byte image).

What it means

Thrown by ImageSource.ResolveDataUri after the base64 payload is successfully decoded but the result is zero bytes. An empty payload is schema-valid and would be silently written as a 0-byte media part, but the picture would render broken in Word/PowerPoint. The guard rejects it up front so the user gets an actionable error instead of a silently corrupted document. This mirrors the extpart carrier's empty-data rejection.

Source

Thrown at src/officecli/Core/ImageSource.cs:142

        var header = dataUri[..commaIdx]; // e.g. "data:image/png;base64"
        var data = dataUri[(commaIdx + 1)..];

        if (!header.Contains("base64", StringComparison.OrdinalIgnoreCase))
            throw new ArgumentException("Only base64-encoded data URIs are supported");

        // Extract MIME type
        var mimeStart = header.IndexOf(':') + 1;
        var mimeEnd = header.IndexOf(';');
        var mime = mimeEnd > mimeStart ? header[mimeStart..mimeEnd] : header[mimeStart..];

        var contentType = MimeToContentType(mime);
        var bytes = Convert.FromBase64String(data);
        // An empty payload decodes "successfully" to zero bytes and would
        // flow all the way into a 0-byte media part — schema-valid, but the
        // picture renders broken in Word/PowerPoint. Reject up front, like
        // the extpart carrier does for empty data.
        if (bytes.Length == 0)
            throw new ArgumentException("Invalid data URI: empty base64 payload (would produce a 0-byte image).");
        return (new MemoryStream(bytes), contentType);
    }

    private static (Stream, PartTypeInfo) ResolveUrl(string url)
    {
        // SSRF guard lives in the shared SsrfGuard so image and file fetch can
        // never diverge in policy. See SsrfGuard for the connect-time / redirect
        // / DNS-rebinding rationale.
        var handler = SsrfGuard.CreateGuardedHandler("image");

        using var client = new HttpClient(handler, disposeHandler: true) { Timeout = TimeSpan.FromSeconds(30) };
        client.DefaultRequestHeaders.Add("User-Agent", "OfficeCLI");

        var response = client.GetAsync(url).GetAwaiter().GetResult();
        response.EnsureSuccessStatusCode();

        // Enforce the shared size cap whether or not the server sends
        // Content-Length. ReadBounded lives in SsrfGuard so image and file

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Ensure the base64 payload contains actual encoded image bytes (not empty).
  2. Verify the source image was read correctly before encoding it to base64.
  3. If building the data URI programmatically, add a length check on the decoded bytes before constructing the URI.

Example fix

// before — empty payload
add image src='data:image/png;base64,' path='/body'

// after — include actual base64 image data
// generate base64: base64 logo.png > logo.b64
add image src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...' path='/body'
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check that the base64 payload decodes to non-zero bytes
if (source.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
{
    int commaIdx = source.IndexOf(',');
    string payload = commaIdx >= 0 ? source[(commaIdx + 1)..] : "";
    try
    {
        byte[] decoded = Convert.FromBase64String(payload);
        if (decoded.Length == 0)
        {
            Console.Error.WriteLine("Data URI payload is empty. Provide actual image data.");
            return;
        }
    }
    catch { /* let ImageSource handle the parse error */ }
}

Try / catch

try
{
    var (stream, contentType) = ImageSource.Resolve(source);
}
catch (ArgumentException ex) when (ex.Message.Contains("empty base64 payload"))
{
    // The source image was empty — provide a valid image and retry
}

Prevention

When it happens

Trigger: Passing a data URI like 'data:image/png;base64,' (base64 flag present, comma present, but the payload after the comma is empty or decodes to nothing). Also triggered by 'data:image/png;base64,=' or other base64 strings that decode to zero bytes. Convert.FromBase64String succeeds (no exception) but returns an empty array.

Common situations: An agent that builds a data URI from a variable that was never populated with image data. A truncation in the data URI where the payload was cut off. A template that left the payload empty as a placeholder. A base64 encoding bug that produced an empty string from valid input.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/b012ce4e94a588cd. Report an issue: GitHub.