<p dir="auto">Requests does not accept headers that are subclasses of string or byte.<br>
They are required i.e. to obfuscate secrets in certain environments, so this is also a security related issue.</p>
<p dir="auto">The issue was introduced by <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/psf/requests/commit/e36f34597ca96c40dbb81d63a8fe9ac0860b8dc3/hovercard" href="https://github.com/psf/requests/commit/e36f34597ca96c40dbb81d63a8fe9ac0860b8dc3"><tt>e36f345</tt></a> at June this year by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/nateprewitt/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/nateprewitt">@nateprewitt</a></p>
<p dir="auto">A possible fix is given in this PR <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1361925370" data-permission-text="Title is private" data-url="https://github.com/psf/requests/issues/6230" data-hovercard-type="pull_request" data-hovercard-url="/psf/requests/pull/6230/hovercard" href="https://github.com/psf/requests/pull/6230">#6230</a></p>
<h2 dir="auto">Expected Result</h2>
<p dir="auto">Headers are used as they are string/byte.</p>
<h2 dir="auto">Actual Result</h2>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/api.py&quot;, line 73, in get
    return request(&quot;get&quot;, url, params=params, **kwargs)
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/api.py&quot;, line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/sessions.py&quot;, line 573, in request
    prep = self.prepare_request(req)
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/sessions.py&quot;, line 484, in prepare_request
    p.prepare(
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/models.py&quot;, line 369, in prepare
    self.prepare_headers(headers)
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/models.py&quot;, line 491, in prepare_headers
    check_header_validity(header)
  File &quot;/tmp/venv/lib64/python3.10/site-packages/requests/utils.py&quot;, line 1037, in check_header_validity
    raise InvalidHeader(
requests.exceptions.InvalidHeader: Header part (Hidden) from {'token': Hidden} must be of type str or bytes, not &lt;class '__main__.Secret'&gt;
"><pre class="notranslate"><code class="notranslate">Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "/tmp/venv/lib64/python3.10/site-packages/requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
  File "/tmp/venv/lib64/python3.10/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File "/tmp/venv/lib64/python3.10/site-packages/requests/sessions.py", line 573, in request
    prep = self.prepare_request(req)
  File "/tmp/venv/lib64/python3.10/site-packages/requests/sessions.py", line 484, in prepare_request
    p.prepare(
  File "/tmp/venv/lib64/python3.10/site-packages/requests/models.py", line 369, in prepare
    self.prepare_headers(headers)
  File "/tmp/venv/lib64/python3.10/site-packages/requests/models.py", line 491, in prepare_headers
    check_header_validity(header)
  File "/tmp/venv/lib64/python3.10/site-packages/requests/utils.py", line 1037, in check_header_validity
    raise InvalidHeader(
requests.exceptions.InvalidHeader: Header part (Hidden) from {'token': Hidden} must be of type str or bytes, not &lt;class '__main__.Secret'&gt;

</code></pre></div>
<h2 dir="auto">Reproduction Steps</h2>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import requests

class Secret(str):
    def __repr__(self):
        return &quot;Hidden&quot;

requests.get(&quot;https://google.com&quot;, headers={&quot;token&quot;: Secret(&quot;Confidential&quot;)})"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">requests</span>

<span class="pl-k">class</span> <span class="pl-v">Secret</span>(<span class="pl-s1">str</span>):
    <span class="pl-k">def</span> <span class="pl-en">__repr__</span>(<span class="pl-s1">self</span>):
        <span class="pl-k">return</span> <span class="pl-s">"Hidden"</span>

<span class="pl-s1">requests</span>.<span class="pl-en">get</span>(<span class="pl-s">"https://google.com"</span>, <span class="pl-s1">headers</span><span class="pl-c1">=</span>{<span class="pl-s">"token"</span>: <span class="pl-v">Secret</span>(<span class="pl-s">"Confidential"</span>)})</pre></div>
<h2 dir="auto">System Information</h2>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ python -m requests.help"><pre class="notranslate"><code class="notranslate">$ python -m requests.help
</code></pre></div>
<div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;chardet&quot;: {
    &quot;version&quot;: null
  },
  &quot;charset_normalizer&quot;: {
    &quot;version&quot;: &quot;2.1.1&quot;
  },
  &quot;cryptography&quot;: {
    &quot;version&quot;: &quot;&quot;
  },
  &quot;idna&quot;: {
    &quot;version&quot;: &quot;3.3&quot;
  },
  &quot;implementation&quot;: {
    &quot;name&quot;: &quot;CPython&quot;,
    &quot;version&quot;: &quot;3.10.6&quot;
  },
  &quot;platform&quot;: {
    &quot;release&quot;: &quot;5.19.6-100.fc35.x86_64&quot;,
    &quot;system&quot;: &quot;Linux&quot;
  },
  &quot;pyOpenSSL&quot;: {
    &quot;openssl_version&quot;: &quot;&quot;,
    &quot;version&quot;: null
  },
  &quot;requests&quot;: {
    &quot;version&quot;: &quot;2.28.1&quot;
  },
  &quot;system_ssl&quot;: {
    &quot;version&quot;: &quot;1010111f&quot;
  },
  &quot;urllib3&quot;: {
    &quot;version&quot;: &quot;1.26.12&quot;
  },
  &quot;using_charset_normalizer&quot;: true,
  &quot;using_pyopenssl&quot;: false
}"><pre class="notranslate">{
  <span class="pl-ent">"chardet"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-c1">null</span>
  },
  <span class="pl-ent">"charset_normalizer"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>2.1.1<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"cryptography"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span><span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"idna"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>3.3<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"implementation"</span>: {
    <span class="pl-ent">"name"</span>: <span class="pl-s"><span class="pl-pds">"</span>CPython<span class="pl-pds">"</span></span>,
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>3.10.6<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"platform"</span>: {
    <span class="pl-ent">"release"</span>: <span class="pl-s"><span class="pl-pds">"</span>5.19.6-100.fc35.x86_64<span class="pl-pds">"</span></span>,
    <span class="pl-ent">"system"</span>: <span class="pl-s"><span class="pl-pds">"</span>Linux<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"pyOpenSSL"</span>: {
    <span class="pl-ent">"openssl_version"</span>: <span class="pl-s"><span class="pl-pds">"</span><span class="pl-pds">"</span></span>,
    <span class="pl-ent">"version"</span>: <span class="pl-c1">null</span>
  },
  <span class="pl-ent">"requests"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>2.28.1<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"system_ssl"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>1010111f<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"urllib3"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>1.26.12<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"using_charset_normalizer"</span>: <span class="pl-c1">true</span>,
  <span class="pl-ent">"using_pyopenssl"</span>: <span class="pl-c1">false</span>
}</pre></div>
<p dir="auto">When using string enums as key values for the <code class="notranslate">headers</code> dict parameter with <code class="notranslate">requests.get()</code> function in <code class="notranslate">v2.28.0</code> it raises an <code class="notranslate">InvalidHeader</code> error but using previous version <code class="notranslate">v2.27.1</code> works well without any error. It seems there was an unexpected breaking change with that release.</p>
<h2 dir="auto">Expected Result</h2>
<p dir="auto">Dict keys for the headers parameter when using <code class="notranslate">requests.get()</code> are still valid if a string enum is used.</p>
<h2 dir="auto">Actual Result</h2>
<p dir="auto">Instead it raises an <code class="notranslate">InvalidHeader</code> error stating that:</p>
<blockquote>
<p dir="auto">Header must be of type <code class="notranslate">str</code> or <code class="notranslate">bytes</code>, not <code class="notranslate">enum</code>.</p>
</blockquote>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="Traceback (most recent call last):
  File &quot;/home/yair/PycharmProjects/tests/requests_error.py&quot;, line 9, in &lt;module&gt;
    requests.get(&quot;http://URL&quot;, headers={CustomEnum.TRACE_ID: &quot;90e85293-afd1-4b48-adf0-fa6daf02359e&quot;})
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/api.py&quot;, line 73, in get
    return request(&quot;get&quot;, url, params=params, **kwargs)
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/api.py&quot;, line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/sessions.py&quot;, line 573, in request
    prep = self.prepare_request(req)
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/sessions.py&quot;, line 484, in prepare_request
    p.prepare(
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/models.py&quot;, line 369, in prepare
    self.prepare_headers(headers)
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/models.py&quot;, line 491, in prepare_headers
    check_header_validity(header)
  File &quot;/home/yair/.local/lib/python3.8/site-packages/requests/utils.py&quot;, line 1037, in check_header_validity
    raise InvalidHeader(
requests.exceptions.InvalidHeader: Header part (&lt;CustomEnum.TRACE_ID: 'X-B3-TraceId'&gt;) from {&lt;CustomEnum.TRACE_ID: 'X-B3-TraceId'&gt;: '90e85293-afd1-4b48-adf0-fa6daf02359e'} must be of type str or bytes, not &lt;enum 'CustomEnum'&gt;"><pre class="notranslate"><span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>):
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/PycharmProjects/tests/requests_error.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">9</span>, <span class="pl-s1">in</span> <span class="pl-c1">&lt;</span><span class="pl-s1">module</span><span class="pl-c1">&gt;</span>
    <span class="pl-s1">requests</span>.<span class="pl-en">get</span>(<span class="pl-s">"http://URL"</span>, <span class="pl-s1">headers</span><span class="pl-c1">=</span>{<span class="pl-v">CustomEnum</span>.<span class="pl-v">TRACE_ID</span>: <span class="pl-s">"90e85293-afd1-4b48-adf0-fa6daf02359e"</span>})
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/api.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">73</span>, <span class="pl-s1">in</span> <span class="pl-s1">get</span>
    <span class="pl-k">return</span> <span class="pl-en">request</span>(<span class="pl-s">"get"</span>, <span class="pl-s1">url</span>, <span class="pl-s1">params</span><span class="pl-c1">=</span><span class="pl-s1">params</span>, <span class="pl-c1">**</span><span class="pl-s1">kwargs</span>)
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/api.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">59</span>, <span class="pl-s1">in</span> <span class="pl-s1">request</span>
    <span class="pl-k">return</span> <span class="pl-s1">session</span>.<span class="pl-en">request</span>(<span class="pl-s1">method</span><span class="pl-c1">=</span><span class="pl-s1">method</span>, <span class="pl-s1">url</span><span class="pl-c1">=</span><span class="pl-s1">url</span>, <span class="pl-c1">**</span><span class="pl-s1">kwargs</span>)
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/sessions.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">573</span>, <span class="pl-s1">in</span> <span class="pl-s1">request</span>
    <span class="pl-s1">prep</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-en">prepare_request</span>(<span class="pl-s1">req</span>)
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/sessions.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">484</span>, <span class="pl-s1">in</span> <span class="pl-s1">prepare_request</span>
    <span class="pl-s1">p</span>.<span class="pl-s1">prepare</span>(
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/models.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">369</span>, <span class="pl-s1">in</span> <span class="pl-s1">prepare</span>
    <span class="pl-s1">self</span>.<span class="pl-en">prepare_headers</span>(<span class="pl-s1">headers</span>)
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/models.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">491</span>, <span class="pl-s1">in</span> <span class="pl-s1">prepare_headers</span>
    <span class="pl-en">check_header_validity</span>(<span class="pl-s1">header</span>)
  <span class="pl-v">File</span> <span class="pl-s">"/home/yair/.local/lib/python3.8/site-packages/requests/utils.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">1037</span>, <span class="pl-s1">in</span> <span class="pl-s1">check_header_validity</span>
    <span class="pl-s1">raise</span> <span class="pl-v">InvalidHeader</span>(
<span class="pl-s1">requests</span>.<span class="pl-s1">exceptions</span>.<span class="pl-v">InvalidHeader</span>: <span class="pl-v">Header</span> <span class="pl-s1">part</span> (<span class="pl-c1">&lt;</span><span class="pl-v">CustomEnum</span>.<span class="pl-v">TRACE_ID</span>: <span class="pl-s">'X-B3-TraceId'</span><span class="pl-c1">&gt;</span>) <span class="pl-k">from</span> {<span class="pl-c1">&lt;</span><span class="pl-v">CustomEnum</span>.<span class="pl-v">TRACE_ID</span>: <span class="pl-s">'X-B3-TraceId'</span><span class="pl-c1">&gt;</span>: <span class="pl-s">'90e85293-afd1-4b48-adf0-fa6daf02359e'</span>} <span class="pl-s1">must</span> <span class="pl-s1">be</span> <span class="pl-s1">of</span> <span class="pl-s1">type</span> <span class="pl-s1">str</span> <span class="pl-c1">or</span> <span class="pl-s1">bytes</span>, <span class="pl-c1">not</span> <span class="pl-c1">&lt;</span><span class="pl-s1">enum</span> <span class="pl-s">'CustomEnum'</span><span class="pl-c1">&gt;</span></pre></div>
<h2 dir="auto">Reproduction Steps</h2>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from enum import Enum
import requests


class CustomEnum(str, Enum):
    TRACE_ID = &quot;X-B3-TraceId&quot;


requests.get(&quot;http://URL&quot;, headers={CustomEnum.TRACE_ID: &quot;90e85293-afd1-4b48-adf0-fa6daf02359e&quot;})"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">enum</span> <span class="pl-k">import</span> <span class="pl-v">Enum</span>
<span class="pl-k">import</span> <span class="pl-s1">requests</span>


<span class="pl-k">class</span> <span class="pl-v">CustomEnum</span>(<span class="pl-s1">str</span>, <span class="pl-v">Enum</span>):
    <span class="pl-v">TRACE_ID</span> <span class="pl-c1">=</span> <span class="pl-s">"X-B3-TraceId"</span>


<span class="pl-s1">requests</span>.<span class="pl-en">get</span>(<span class="pl-s">"http://URL"</span>, <span class="pl-s1">headers</span><span class="pl-c1">=</span>{<span class="pl-v">CustomEnum</span>.<span class="pl-v">TRACE_ID</span>: <span class="pl-s">"90e85293-afd1-4b48-adf0-fa6daf02359e"</span>})</pre></div>
<h2 dir="auto">System Information</h2>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ python -m requests.help"><pre class="notranslate"><code class="notranslate">$ python -m requests.help
</code></pre></div>
<div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;chardet&quot;: {
    &quot;version&quot;: &quot;3.0.4&quot;
  },
  &quot;charset_normalizer&quot;: {
    &quot;version&quot;: &quot;2.0.4&quot;
  },
  &quot;cryptography&quot;: {
    &quot;version&quot;: &quot;2.8&quot;
  },
  &quot;idna&quot;: {
    &quot;version&quot;: &quot;3.2&quot;
  },
  &quot;implementation&quot;: {
    &quot;name&quot;: &quot;CPython&quot;,
    &quot;version&quot;: &quot;3.8.10&quot;
  },
  &quot;platform&quot;: {
    &quot;release&quot;: &quot;5.13.0-48-generic&quot;,
    &quot;system&quot;: &quot;Linux&quot;
  },
  &quot;pyOpenSSL&quot;: {
    &quot;openssl_version&quot;: &quot;1010106f&quot;,
    &quot;version&quot;: &quot;19.0.0&quot;
  },
  &quot;requests&quot;: {
    &quot;version&quot;: &quot;2.28.0&quot;
  },
  &quot;system_ssl&quot;: {
    &quot;version&quot;: &quot;1010106f&quot;
  },
  &quot;urllib3&quot;: {
    &quot;version&quot;: &quot;1.26.6&quot;
  },
  &quot;using_charset_normalizer&quot;: false,
  &quot;using_pyopenssl&quot;: true
}"><pre class="notranslate">{
  <span class="pl-ent">"chardet"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>3.0.4<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"charset_normalizer"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>2.0.4<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"cryptography"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>2.8<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"idna"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>3.2<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"implementation"</span>: {
    <span class="pl-ent">"name"</span>: <span class="pl-s"><span class="pl-pds">"</span>CPython<span class="pl-pds">"</span></span>,
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>3.8.10<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"platform"</span>: {
    <span class="pl-ent">"release"</span>: <span class="pl-s"><span class="pl-pds">"</span>5.13.0-48-generic<span class="pl-pds">"</span></span>,
    <span class="pl-ent">"system"</span>: <span class="pl-s"><span class="pl-pds">"</span>Linux<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"pyOpenSSL"</span>: {
    <span class="pl-ent">"openssl_version"</span>: <span class="pl-s"><span class="pl-pds">"</span>1010106f<span class="pl-pds">"</span></span>,
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>19.0.0<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"requests"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>2.28.0<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"system_ssl"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>1010106f<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"urllib3"</span>: {
    <span class="pl-ent">"version"</span>: <span class="pl-s"><span class="pl-pds">"</span>1.26.6<span class="pl-pds">"</span></span>
  },
  <span class="pl-ent">"using_charset_normalizer"</span>: <span class="pl-c1">false</span>,
  <span class="pl-ent">"using_pyopenssl"</span>: <span class="pl-c1">true</span>
}</pre></div>