journal · 5 august 2026
A Windows bug in the Kubernetes Python client
Notes on a bug that only happened on Windows, the change that fixed it, and the follow up PR for the same problem in the asyncio client.
- Project
- kubernetes-client/python, the official Python client for the Kubernetes API
- Language
- Python
- Change
- 1 file, 4 lines added, 6 removed
- Merged
- 4 August 2026 into master, opened 21 July
The bug
If a kubeconfig authenticates through OIDC and includes idp-certificate-authority-data, the client writes that certificate to disk so it can pass the path to the TLS layer. The code created a NamedTemporaryFile and then opened it a second time by name to write to it.
ca_cert = tempfile.NamedTemporaryFile(delete=True)
cert = base64.b64decode(
provider['config']['idp-certificate-authority-data']
).decode('utf-8')
with open(ca_cert.name, 'w') as fh:
fh.write(cert)
config.ssl_ca_cert = ca_cert.name
This works on Linux and macOS. On Windows the second open raises PermissionError. Windows holds the file exclusively while the first handle is open, and NamedTemporaryFile keeps its handle open until the object is collected.
So on Windows, OIDC token refresh raised an exception at runtime for any kubeconfig using that field.
The library is developed and tested mostly on Linux, where the bug does not appear. I ran the config test suite on Windows 11 and test_oidc_with_refresh failed.
The fix
The module already had a helper for this, _create_temp_file_with_content, used elsewhere in the same file for other inline certificate data. It uses mkstemp, closes the descriptor before anything reopens the path, and cleans up through the existing atexit handler. The change routes this call site through it.
cert = base64.b64decode(
provider['config']['idp-certificate-authority-data']
).decode('utf-8')
# Use the shared temp-file helper instead of reopening a
# NamedTemporaryFile by name, which fails with PermissionError
# on Windows while the original handle is still open.
config.ssl_ca_cert = _create_temp_file_with_content(cert)
The patch is four lines added and six removed, in one file. No test changes were needed. test_oidc_with_refresh already covered the path, so once the production code was fixed it passed. I ran the config suite on Windows 11 and put the result in the PR description: 75 passed.
It was opened on 21 July and merged on 4 August.
The asyncio client
After review, the approver asked whether the asyncio client had the same problem.
It did, in a different form. The async version writes through the open handle instead of reopening the path, so it does not produce the same traceback. But it passes certfile.name to OpenIDRequestor while the handle is still open, so anything that opens the CA cert by path fails on Windows instead.
I ran both temp file patterns on Windows 11 and Python 3.14 to confirm before answering:
new helper: reopened by path OK, 59 bytes
old pattern: PermissionError [Errno 13] Permission denied
The follow up is open as #2668. It is larger, 40 lines added and 30 removed, because the aio module had no module level helper to reuse, only a method on FileOrData. The change adds one that mirrors the sync module and points the existing method at it. It also closes a file descriptor the old method leaked, since it discarded the fd returned by mkstemp without closing it.
The CA cert temp file used to be removed when the with block ended. It now lives until process exit under the atexit hook, which matches the sync client. That is a real change rather than a refactor, so it is described in the PR body.
Notes
- The bug was only visible on Windows, in a code path that already had a test covering it. Running the suite on a platform the project does not test on found it.
- I did not know whether the asyncio client had the same problem, so I ran both patterns and posted the output rather than giving an opinion.
- Using the helper that was already in the file meant there was no new approach for the reviewer to evaluate.
- The behaviour change in the async PR is stated in the description instead of being left for the reviewer to find.