Repository navigation
Python: Percent-encoded base64 data URIs fail media type detection #9653
Description
Observed Behavior
detect_media_type_from_base64(data_uri=...) rejects a valid base64 data URL when its payload contains URL-escaped characters. Encoding / as %2F changes an otherwise working PNG input into ValueError: Invalid base64 data provided.
Content.from_uri accepts both representations and identifies the same media type, but the internal byte-extraction helper also fails on the escaped representation. No provider request is needed to observe this.
Expected Behavior
Equivalent literal and URL-escaped base64 payloads should yield the same media detection result and decoded bytes. The Fetch data-URL processing algorithm percent-decodes the body before base64 decoding. Python's built-in data handler reads identical bytes for both inputs below.
Steps to Reproduce
Compare the literal and percent-encoded forms of the same small PNG data URL using the public media-detection helper. The literal form returns image/png; the equivalent escaped form raises an exception.
Minimal Reproduction
from urllib.parse import quote
from urllib.request import urlopen
from agent_framework import detect_media_type_from_base64
payload = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC"
literal = "data:image/png;base64," + payload
escaped = "data:image/png;base64," + quote(payload, safe="")
# These are local data URLs; this does not contact a server.
with urlopen(literal) as first, urlopen(escaped) as second:
assert first.read() == second.read()
print(detect_media_type_from_base64(data_uri=literal)) # image/png
print(detect_media_type_from_base64(data_uri=escaped)) # raises ValueErrorError Messages and Stack Traces
ValueError: Invalid base64 data provided.
Package Versions
Source snapshot at 678c6616aa4c73ecfc28cc6fc119a3928ba04024; _types.py blob 629593b8839f6828887af9668462ef7ba2fea837. The run loaded the seven complete, unchanged source modules required by the official agent_framework initializer and these public exports. It reused an existing environment with typing-extensions 4.16.0. This was not a fresh installation or a complete SDK test; the environment's installed agent-framework-core 1.19.0 metadata does not identify the source snapshot.
Python Version
CPython 3.14.3, x64
Operating System
Windows
Regression
Unknown
Additional Context
The 69-byte PNG is a complete 1x1 image with computed chunk CRCs. Its literal data URL is the normal control; its URL-escaped form contains identical bytes. Content.from_data also preserves those bytes. The initial module-level observation and the later public-export verification use this same PNG, not additional independent cases.
The current _parse_data_uri leaves the payload URL-escaped, and both detection and byte extraction pass it to the base64 decoder. This is separate from #8905/#8918, which addressed URI parameters, media-type defaults and validation. No production patch has been started. Would decoding the payload's URL escapes before base64 processing be the appropriate direction?
No provider/cloud calls, image rendering, complete SDK suite, other Python versions or other operating systems were tested.
AI assistance: Reproduction analysis and this issue description.
Acknowledgements
- I searched existing issues and did not find a duplicate.
- I personally verified this behavior and the reproduction details are authentic.
- I will wait for explicit maintainer agreement before starting implementation of a non-trivial change.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
MuonChaser commentedon Oct 23, 2026
I’ll take this on as a bounded data-URI compatibility fix: percent-decode the payload once before base64 processing, preserving literal
+, raw-input behavior, and existing metadata/error handling. I’ll add offline regressions for media detection and Content byte extraction, including escaped/,+,=, and double-encoding.ktz03 commentedon Oct 23, 2026
I'd like to implement this fix once the maintainers confirm the direction; the report and normal-control reproduction are ready. Zhang Bowen (@MuonChaser), have you already started a patch? Please let me know so we can agree on who implements it and avoid duplicate work.
MuonChaser commentedon Oct 24, 2026
LI (@ktz03) Yes—the patch was already completed locally before your reply. I've opened #9664: it decodes the payload once, preserves literal
+, and adds offline regressions for detection and byte extraction, including nested escapes. I'm happy to carry this PR through review so we can avoid parallel patches. No maintainer approval is claimed; the PR explains the bounded trivial-correction rationale. Thanks for the clear reproduction.ktz03 commentedon Oct 24, 2026
Zhang Bowen (@MuonChaser) Thanks for the update. As the reporter, I would like to implement and maintain the fix myself. Would you be willing to hand off this work so I can submit the repair PR, and coordinate superseding #9664? I would preserve your attribution for any code or tests I reuse.