Skip to content

Comments

Fix base64 deserialization when JSON encoder escapes forward slashes#1342

Open
Copilot wants to merge 2 commits intomainfrom
copilot/fix-imagecontentblock-base64-error
Open

Fix base64 deserialization when JSON encoder escapes forward slashes#1342
Copilot wants to merge 2 commits intomainfrom
copilot/fix-imagecontentblock-base64-error

Conversation

Copy link
Contributor

Copilot AI commented Feb 21, 2026

ImageContentBlock, AudioContentBlock, and BlobResourceContents fail with FormatException: Invalid base64 data when the upstream JSON encoder escapes / as \/ in base64 strings — a valid JSON escape that many encoders produce.

The custom converters used reader.ValueSpan.ToArray() which returns raw unescaped bytes. The literal \ from \/ escapes is not a valid base64 character, so Base64.DecodeFromUtf8 rejects it.

Changes

  • ContentBlock.Converter.Read and ResourceContents.Converter.Read: Check reader.ValueIsEscaped; when true, fall back to reader.GetString() + Encoding.UTF8.GetBytes() to get properly unescaped UTF-8 bytes. The fast ValueSpan path is preserved for the common case.
  • Added tests for all three types verifying round-trip through escaped base64 containing /.
case "data":
    if (!reader.ValueIsEscaped)
    {
        data = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan.ToArray();
    }
    else
    {
        data = Encoding.UTF8.GetBytes(reader.GetString()!);
    }
    break;
Original prompt

This section details on the original issue you should resolve

<issue_title>0.9.0-preview.1: ImageContentBlock throws "invalid base64" when consuming CallToolResult (works in 0.8.0-preview.1)</issue_title>
<issue_description>

Title

0.9.0-preview.1: ImageContentBlock throws "invalid base64" when consuming CallToolResult (works in 0.8.0-preview.1)


Description

After upgrading from ModelContextProtocol 0.8.0-preview.1 to 0.9.0-preview.1, consuming an MCP server CallToolResult that includes an ImageContentBlock now throws an "invalid base64" exception.

The exact same MCP server response works correctly in:

  • 0.8.0-preview.1
  • Postman (image renders correctly)

This appears to be a regression introduced in 0.9.0-preview.1, possibly related to the change of ImageContentBlock.Data from string to ReadOnlyMemory<byte> and how JSON deserialization handles base64 content.


Expected Behavior

CallToolResult containing an ImageContentBlock should deserialize successfully and allow access to the image data (via DecodedData or Data) without throwing.

This worked correctly in 0.8.0-preview.1.


Actual Behavior

When consuming the tool result:

  • Accessing ImageContentBlock causes an "invalid base64" exception.
  • In some cases, accessing DecodedData triggers the exception.
  • The same payload renders correctly in Postman.
  • The server response contains valid base64 (confirmed visually and by rendering in Postman).

Repro Steps

  1. Use ModelContextProtocol 0.9.0-preview.1
  2. Connect to MCP server
  3. Invoke a tool that returns an ImageContentBlock
  4. Receive CallToolResult
  5. Access image content (e.g., DecodedData)

Result: FormatException / invalid base64 error

Reverting to 0.8.0-preview.1 resolves the issue immediately.


Sample Tool Result Payload (Redacted)

{
  "content": [
    {
      "type": "image",
      "mimeType": "image/png",
      "data": "<valid base64 string>"
    }
  ]
}

Notes:

  • No data:image/... prefix
  • Standard base64 alphabet
  • Image renders correctly in Postman

Environment

  • ModelContextProtocol: 0.9.0-preview.1
  • .NET: (e.g. .NET 10)
  • OS: (Windows)

Additional Context

This appears to be related to the 0.9 change where ImageContentBlock.Data is now ReadOnlyMemory<byte>. It may be caused by stricter base64 handling during JSON deserialization or a double-decode scenario.


</issue_description>

<agent_instructions>Fix this issue and ensure there are appropriate tests. One theory about the root cause and fix is in the benchcopilot/reproduce-issue-1340</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…k, AudioContentBlock, and BlobResourceContents

The ContentBlock.Converter and ResourceContents.Converter were using
reader.ValueSpan.ToArray() to read base64-encoded data from JSON strings.
This reads raw bytes without unescaping JSON escape sequences. When base64
data contains '/' characters that are JSON-escaped as '\/' (a valid JSON
escape used by some encoders), the backslash corrupts the base64 data,
causing "Invalid base64 data" FormatException on access to DecodedData.

Fix: Check reader.ValueIsEscaped and fall back to GetString() + UTF8
encoding when escape sequences are present, preserving the fast path
for the common unescaped case.

Fixes #1340

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
}
else
{
data = Encoding.UTF8.GetBytes(reader.GetString()!);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ericstj seems like this will be the majority case, such that the switch in representation is actually going to make these cases worse?

@stephentoub stephentoub marked this pull request as ready for review February 21, 2026 05:33
Copilot AI changed the title [WIP] Fix invalid base64 error in ImageContentBlock Fix base64 deserialization when JSON encoder escapes forward slashes Feb 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0.9.0-preview.1: ImageContentBlock throws "invalid base64" when consuming CallToolResult (works in 0.8.0-preview.1)

2 participants