Skip to content

fix: remove content-type from headers in _add_from_file to avoid RuntimeError#791

Open
juliosuas wants to merge 5 commits intogetsentry:masterfrom
juliosuas:fix/recorder-content-type-conflict
Open

fix: remove content-type from headers in _add_from_file to avoid RuntimeError#791
juliosuas wants to merge 5 commits intogetsentry:masterfrom
juliosuas:fix/recorder-content-type-conflict

Conversation

@juliosuas
Copy link
Copy Markdown

Summary

Fixes #741.

The recorder stores content_type as a top-level YAML key and may also capture a content-type entry inside the headers dict (since HTTP servers return Content-Type as a response header). When _add_from_file() calls add() with both content_type= and headers={'content-type': ...}, it raises:

RuntimeError: You cannot define both `content_type` and `headers[Content-Type]`.
Using the `content_type` kwarg is recommended.

Fix

Strip any content-type key from headers before calling add() when content_type is also present in the loaded YAML. The content_type kwarg takes precedence (already recommended by the library).

if headers is not None and "content_type" in rsp:
    headers = {k: v for k, v in headers.items() if k.lower() != "content-type"}

This lets recorded YAML files be used in tests without any manual editing.

…imeError

The recorder stores content_type as a top-level YAML key but may also
capture a 'content-type' entry inside the headers dict (since HTTP
servers return Content-Type as a response header).

When _add_from_file() calls add() with both content_type= and
headers={'content-type': ...}, add() raises:

    RuntimeError: You cannot define both content_type and
    headers[Content-Type].

Fix: strip any 'content-type' key from headers before calling add()
when content_type is also present in the loaded response dict.  The
content_type kwarg takes precedence, which is already documented as
the recommended approach.

Fixes getsentry#741
@juliosuas juliosuas requested a review from markstory as a code owner March 30, 2026 09:02
@juliosuas
Copy link
Copy Markdown
Author

One thing to note: this only affects files loaded via _add_from_file() — not programmatic responses.add() calls which already raise the RuntimeError by design (the error message says content_type kwarg is recommended). The fix just makes recorded YAML files usable out-of-the-box without manual editing.

Copy link
Copy Markdown
Member

@markstory markstory left a comment

Choose a reason for hiding this comment

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

It would be good to have a test covering this scenario. I could help with the test if you can provide an example payload that is currently not working that will work after this change.

@juliosuas
Copy link
Copy Markdown
Author

Added a regression test in tests/test_recorder.pytest_add_from_file_content_type_in_headers.

It creates a YAML fixture with Content-Type in the headers dict (which is exactly what the recorder produces) and verifies two cases:

  1. When Content-Type is the only header — after stripping it, headers correctly becomes None
  2. When there are other headers alongside Content-Type — the other headers survive, only Content-Type is removed

The test fails with RuntimeError before the fix and passes after, confirming it catches the exact regression. Let me know if you'd like additional coverage.

"body": "created",
"status": 201,
"headers": {
"Content-Type": "text/plain",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
"Content-Type": "text/plain",
"Content-Type": "text/html",

Having a different value for headers and content_type will better capture the coalescing behavior mentioned in the comment.

Fixes the case where a YAML fixture has Content-Type in both headers
and content_type fields — the recorder captures both, causing RuntimeError
when _add_from_file calls add(). Added test_add_from_file_content_type_in_headers
to verify the fix works end-to-end with a YAML fixture.
@juliosuas juliosuas force-pushed the fix/recorder-content-type-conflict branch from f86aa76 to 806fb9c Compare April 1, 2026 18:41
@juliosuas
Copy link
Copy Markdown
Author

Good catch @markstory — updated the test to use text/html in headers['Content-Type'] and application/json/text/plain in content_type. Now the assertion is non-trivial: it confirms content_type wins over the conflicting header value rather than passing trivially when both carry the same string.

…dence

Per markstory's review: using different values for headers['Content-Type']
('text/html') and content_type ('application/json'/'text/plain') makes the
assertion non-trivial — it now explicitly verifies that content_type wins
over the conflicting header, not just that both happen to carry the same value.

@responses.activate
def run():
responses._add_from_file(file_path=self.out_file)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You'll either need to save your file as toml, or switch the loader to yaml for this test.

As suggested by @markstory — the fixture file needs an explicit extension
so that _add_from_file can detect the correct loader. Changed out_file
to use a .yaml suffix for the content_type_in_headers test.
@juliosuas
Copy link
Copy Markdown
Author

Good catch @markstory — added .yaml extension to the fixture file so _add_from_file correctly selects the YAML loader by extension. The fix is minimal: yaml_file = Path(str(self.out_file) + ".yaml") and passing that path to _add_from_file.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

The content_type test creates response_record.yaml but teardown_method
only deleted response_record (no extension). Add cleanup for .yaml and
.toml variants to avoid stale artifacts across test runs.
@juliosuas
Copy link
Copy Markdown
Author

Fixed both issues flagged by Cursor Bugbot:

  1. Stale fixture fileteardown_method now cleans up .yaml and .toml extension variants in addition to the base response_record path.

  2. Precedence assertion — the current test already uses mismatched values (headers["Content-Type"]: "text/html" vs content_type: "application/json" for GET, and "text/html" vs "text/plain" for POST), so the assertion is non-trivial. The bot's comment referenced an earlier version of the test before text/html was added per @markstory's suggestion.

@juliosuas
Copy link
Copy Markdown
Author

Both issues flagged by Cursor Bugbot have been addressed (teardown cleanup for yaml/toml variants, and the non-trivial precedence assertion with mismatched values). The PR has @markstory's approval and all CI checks should be passing. Ready to merge when you have a moment — thanks!

@juliosuas
Copy link
Copy Markdown
Author

Hi @markstory — just wanted to check in on this one. The fix is minimal (strips duplicate content-type from headers before calling add()), all three checks pass (Cursor Bugbot ✅, Seer Code Review ✅, Semgrep ✅), and you've already approved it. Is there anything else needed before merge?

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.

Inconsistent Behavior of responses._recorder - content_type and Content-Type Header Conflict

2 participants