Skip to content

Python: Reject every multi-source combination in detect_media_type_from_base64 - #8557

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 4 commits into
microsoft:mainfrom
sxh313:fix/detect-media-type-exclusive-sources
Sep 21, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 4 commits into
microsoft:mainfrom
sxh313:fix/detect-media-type-exclusive-sources

Conversation

@sxh313

Copy link
Copy Markdown
Contributor

Motivation & Context

detect_media_type_from_base64() documents that exactly one of data_bytes, data_str, or data_uri
must be provided, and raises ValueError otherwise. That contract was not enforced for one
combination: data_str together with data_uri.

The guard compared data is not None, but data only ever mirrors data_bytes. When a data URI is
supplied, its payload is rebound into the data_str local variable (prefix, data_str = data_uri.split(",", 1)),
so by the time the data_str branch runs, the caller's data_str is gone. The call was accepted and the
URI silently won:

>>> detect_media_type_from_base64(
...     data_str="invalid_base64!",
...     data_uri="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg==",
... )
'image/png'   # no error, the caller's base64 argument was discarded

This is the root cause of the second block reported in #5115: five of the six documented cases sat inside a
single with pytest.raises(...) block, so only the first ever executed and the bug stayed invisible.

Description & Review Guide

  • What are the major changes?
    • python/packages/core/agent_framework/_types.py: the mutual-exclusion check inside the data_uri branch
      now also covers a caller-supplied data_str, i.e. it runs before the URI payload is rebound into that
      variable.
    • python/packages/core/tests/core/test_types.py: the two multi-statement pytest.raises blocks are split
      into one parametrized test that exercises every rejected combination (each in its own raises block) plus a
      regression test that asserts the specific data_str + data_uri case.
  • What is the impact of these changes?
    Every input that supplies zero or more than one source now raises
    ValueError("Provide exactly one of data_bytes, data_str, or data_uri."), matching the docstring. Single-source
    behavior is unchanged. No new error type, message, or signature change, so callers that used the API as
    documented are unaffected.
  • What do you want reviewers to focus on?
    Whether data_bytes + data_str + data_uri (all three) should keep the same message, which it does here,
    and whether you prefer this ordering fix over hoisting a single upfront sum(...) != 1 guard.

Deliberately out of scope: the first block of #5115 also notes that data_str="" returns None rather than
raising. That needs the maintainer decision recorded in the issue (whether an empty string is valid input or
should be rejected), so this PR only removes the dead statement and leaves the behavior as is.
The closed PR #5171 changed tests only; it did not fix the source and did not cover the silent
data_str + data_uri acceptance.

Related Issue

Fixes #5115

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

…om_base64

The mutual-exclusion guard read a variable that only mirrored data_bytes,
while the data URI payload was rebound into data_str, so passing both
data_str and data_uri was silently accepted (the URI won) instead of
raising. Move the check ahead of the rebind and split the pytest.raises
blocks that hid the untested combinations.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation enforces the documented contract and the tests cover every invalid source combination.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes mutual-exclusion validation for base64 media-type detection and strengthens regression coverage.

Changes:

  • Rejects data_str combined with data_uri.
  • Parametrizes all invalid source combinations.
  • Removes previously unreachable test code.
File Description
python/​packages/​core/​agent_framework/​_types.py Validates conflicting inputs before rebinding URI data.
python/​packages/​core/​tests/​core/​test_types.py Tests each invalid input combination independently.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

@sxh313
sxh (sxh313) force-pushed the fix/detect-media-type-exclusive-sources branch from cd0b324 to a2d7f08 Compare September 20, 2026 16:59
@sxh313
sxh (sxh313) deployed to github-app-auth September 20, 2026 16:59 — with GitHub Actions Active
@sxh313
sxh (sxh313) deployed to github-app-auth September 21, 2026 02:41 — with GitHub Actions Active
@moonbox3

Copy link
Copy Markdown
Contributor

sxh (sxh (@sxh313)) please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

sxh (@sxh313) please accept the CLA

@sxh313

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@sxh313
sxh (sxh313) deployed to github-app-auth September 21, 2026 09:39 — with GitHub Actions Active
@sxh313

Copy link
Copy Markdown
Contributor Author

Thanks for the review and the nudge on the CLA - signed now, and license/cla is green.

I also brought the branch up to date with main (head is now 8835e7276), so the earlier merge-gatekeeper failure (Timed out waiting for: license/cla) has nothing left to wait for. One thing that needs a human: because this comes from a fork, the six pull_request runs on the new head are sitting in action_required (Code Quality, Tests, Test Coverage, Merge - Tests, dotnet-build-and-test, Merge Gatekeeper), so they will not start until someone with write access approves them. Public API Compatibility and add_label already ran and passed.

No action needed from you beyond the approve-and-run click - happy to answer anything in the meantime.

Merged via the queue into microsoft:main with commit 70d739d Sep 21, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: pytest.raises wrong usage (dead code and unexpected behaviour)

4 participants