Let me begin by stating that I'm primarily an Ansible content developer and user. I make heavy use of the azure.azcollection for Azure configuration management and general purpose automation. The azure.azcollection depends upon ms-graph-sdk, msgraph-core, and friends.
I came across this odd bug after patching my local system (Ubuntu 22.04.05 LTS) in the past couple/few days and it took me hours to track it down (sadly, I had to resort to Gemini/Claude assistance to track it down in a timely manner).
Bottom line, the root cause of the bug appears to be a local kernel update, where uname -v has whitespace at the end. I have a local patch in place inside telemetry.py, but I figure'd I'd share this report.
What follows is the result of my Claude/Gemini session identifying and patching the bug.
Describe the bug
TelemetryHandler._add_host_os_header sets the HostOs header to the raw value of platform.system() + " " + platform.version() without any sanitization:
# msgraph_core/middleware/telemetry.py
def _add_host_os_header(self, request) -> None:
system = platform.system()
version = platform.version()
host_os = f'{system} {version}'
request.headers.update({'HostOs': host_os})
platform.version() is whatever the OS reports for the kernel build string, and the SDK has no control over its contents. On some hosts this string contains leading/trailing whitespace (or other characters that are illegal in an HTTP header value). When it does, every request fails before it is sent, because h11 (via httpx/httpcore) rejects the header:
httpcore.LocalProtocolError: Illegal header value b'Linux #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC '
(Note the trailing space — h11 rejects header values with leading/trailing whitespace.)
Expected behavior
Telemetry headers should be sanitized so a malformed platform.version() cannot crash requests — e.g. strip whitespace (and ideally collapse/replace any remaining illegal characters), or omit the header if it cannot be made valid. Telemetry must be best-effort and non-fatal.
How to reproduce
Any host whose platform.version() contains a trailing space (or other illegal header byte). Minimal reproduction of the failing condition:
import platform
from h11._headers import normalize_and_validate
# Simulating a host whose kernel build string ends with a trailing space:
version = "#124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC "
host_os = f"{platform.system()} {version}"
normalize_and_validate([(b"HostOs", host_os.encode())])
# -> h11._util.LocalProtocolError: Illegal header value b'Linux ... UTC '
In practice this surfaces through any Graph call. Real-world report: the Ansible azure.azcollection.azure_rm_adapplication module fails on the first GET /applications with the traceback above, on an Ubuntu 22.04 host (kernel 6.8.0-124-generic) whose uname -v ends with a trailing space and no year.
Suggested fix
host_os = f'{system} {version}'.strip()
A more defensive version would also collapse internal whitespace / drop non-token bytes, but .strip() resolves the reported case.
Environment
msgraph-core 1.1.3 (also present unchanged on main and through v1.4.0)
msgraph-sdk 1.6.0
httpx with h11 0.14.0
- Python 3.10
- OS: Ubuntu 22.04, kernel
6.8.0-124-generic
Full traceback (abridged)
File ".../msgraph_core/middleware/telemetry.py", line 48, in send
response = await super().send(request, transport)
...
File ".../httpcore/_async/http11.py", line 151, in _send_request_headers
with map_exceptions({h11.LocalProtocolError: LocalProtocolError}):
File ".../httpcore/_exceptions.py", line 14, in map_exceptions
raise to_exc(exc) from exc
httpcore.LocalProtocolError: Illegal header value b'Linux #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC '
The above exception was the direct cause of the following exception:
...
httpx.LocalProtocolError: Illegal header value b'Linux #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC '
Let me begin by stating that I'm primarily an Ansible content developer and user. I make heavy use of the
azure.azcollectionfor Azure configuration management and general purpose automation. Theazure.azcollectiondepends upon ms-graph-sdk, msgraph-core, and friends.I came across this odd bug after patching my local system (Ubuntu 22.04.05 LTS) in the past couple/few days and it took me hours to track it down (sadly, I had to resort to Gemini/Claude assistance to track it down in a timely manner).
Bottom line, the root cause of the bug appears to be a local kernel update, where
uname -vhas whitespace at the end. I have a local patch in place insidetelemetry.py, but I figure'd I'd share this report.What follows is the result of my Claude/Gemini session identifying and patching the bug.
Describe the bug
TelemetryHandler._add_host_os_headersets theHostOsheader to the raw value ofplatform.system() + " " + platform.version()without any sanitization:platform.version()is whatever the OS reports for the kernel build string, and the SDK has no control over its contents. On some hosts this string contains leading/trailing whitespace (or other characters that are illegal in an HTTP header value). When it does, every request fails before it is sent, becauseh11(viahttpx/httpcore) rejects the header:(Note the trailing space —
h11rejects header values with leading/trailing whitespace.)Expected behavior
Telemetry headers should be sanitized so a malformed
platform.version()cannot crash requests — e.g. strip whitespace (and ideally collapse/replace any remaining illegal characters), or omit the header if it cannot be made valid. Telemetry must be best-effort and non-fatal.How to reproduce
Any host whose
platform.version()contains a trailing space (or other illegal header byte). Minimal reproduction of the failing condition:In practice this surfaces through any Graph call. Real-world report: the Ansible
azure.azcollection.azure_rm_adapplicationmodule fails on the firstGET /applicationswith the traceback above, on an Ubuntu 22.04 host (kernel6.8.0-124-generic) whoseuname -vends with a trailing space and no year.Suggested fix
A more defensive version would also collapse internal whitespace / drop non-token bytes, but
.strip()resolves the reported case.Environment
msgraph-core1.1.3 (also present unchanged onmainand through v1.4.0)msgraph-sdk1.6.0httpxwithh110.14.06.8.0-124-genericFull traceback (abridged)