Title: [3.15] Re-entrant calls to `site.addsitedir()` can fail (affecting uv run) · Issue #149504 · python/cpython · GitHub
Open Graph Title: [3.15] Re-entrant calls to `site.addsitedir()` can fail (affecting uv run) · Issue #149504 · python/cpython
X Title: [3.15] Re-entrant calls to `site.addsitedir()` can fail (affecting uv run) · Issue #149504 · python/cpython
Description: Bug report Bug description: I found a regression in Python 3.15’s site.py startup-file processing. A .pth file containing an import line that calls site.addsitedir() can re-enter process_startup_files() while _exec_imports() is iterating...
Open Graph Description: Bug report Bug description: I found a regression in Python 3.15’s site.py startup-file processing. A .pth file containing an import line that calls site.addsitedir() can re-enter process_startup_fi...
X Description: Bug report Bug description: I found a regression in Python 3.15’s site.py startup-file processing. A .pth file containing an import line that calls site.addsitedir() can re-enter process_startup_fi...
Opengraph URL: https://github.com/python/cpython/issues/149504
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[3.15] Re-entrant calls to `site.addsitedir()` can fail (affecting uv run)","articleBody":"# Bug report\n\n### Bug description:\n\nI found a regression in Python 3.15’s `site.py` startup-file processing. A `.pth` file containing an import line that calls `site.addsitedir()` can re-enter `process_startup_files()` while `_exec_imports()` is iterating `_pending_importexecs`, causing recursive processing of the same `.pth` file and eventually a startup failure.\n\nThis was originally observed with `uv run --with ...`, because uv creates an ephemeral overlay `.pth` file like:\n\n```python\nimport site; site.addsitedir(\"/path/to/overlay/site-packages\"); site.addsitedir(\"/usr/local/lib/python3.15/site-packages\")\n```\n\nBut the issue can be reproduced without uv.\n\n**Environment**\n\n```text\nPython 3.15.0b1+ (heads/3.15:e81025e6d2e, May 7 2026, 10:29:46)\n[Clang 15.0.0 (clang-1500.3.9.4)]\nmacOS arm64\n```\n\n**Minimal Reproducer**\n\n```bash\nmkdir -p /tmp/site-repro/root /tmp/site-repro/overlay\nprintf 'import site; site.addsitedir(\"/tmp/site-repro/overlay\")\\n' \u003e /tmp/site-repro/root/reenter.pth\n\npython3.15 -S -c 'import site; site.addsitedir(\"/tmp/site-repro/root\"); print(\"done\")'\n```\n\n**Expected Behavior**\n\nThe `.pth` import line should execute once, add `/tmp/site-repro/overlay` as a site directory, and the command should print:\n\n```text\ndone\n```\n\n**Actual Behavior**\n\nPython repeatedly processes the same `.pth` import line, then fails with errors like:\n\n```text\nError in import line from /tmp/site-repro/root/reenter.pth: import site; site.addsitedir(\"/tmp/site-repro/overlay\")\n...\nRuntimeError: dictionary changed size during iteration\n```\n\nIn startup contexts, such as `uv run --with ...`, this can become fatal during `site` initialization:\n\n```text\nFatal Python error: init_import_site: Failed to import the site module\nPython runtime state: core initialized\nTraceback (most recent call last):\n File \"\u003cfrozen site\u003e\", line 901, in \u003cmodule\u003e\n File \"\u003cfrozen site\u003e\", line 877, in main\n File \"\u003cfrozen site\u003e\", line 812, in venv\n File \"\u003cfrozen site\u003e\", line 598, in addsitepackages\n File \"\u003cfrozen site\u003e\", line 422, in addsitedir\n File \"\u003cfrozen site\u003e\", line 359, in process_startup_files\n File \"\u003cfrozen site\u003e\", line 303, in _exec_imports\nRuntimeError: dictionary changed size during iteration\n```\n\n**Likely Cause**\n\nIn `Lib/site.py`, `addsitedir()` calls `process_startup_files()` unless `defer_processing_start_files=True`.\n\n`process_startup_files()` calls `_exec_imports()`, which iterates directly over `_pending_importexecs.items()`:\n\n```python\ndef _exec_imports():\n for filename, imports in _pending_importexecs.items():\n ...\n for line in imports:\n exec(line)\n```\n\nIf one of those `.pth` import lines calls `site.addsitedir()`, then `addsitedir()` calls `process_startup_files()` again while the outer `_exec_imports()` is still iterating `_pending_importexecs`. That causes repeated execution and eventually `RuntimeError: dictionary changed size during iteration`.\n\n**Real-World Trigger**\n\nWith uv 0.11.7:\n\n```bash\nuv run --python /Users/jelle/py/cpython/python.exe --with iniconfig python -c 'import iniconfig'\n```\n\nfails before user code runs because uv’s ephemeral overlay `.pth` contains `import site; site.addsitedir(...)`.\n\nPlain `uv run` without `--with` works, so this is specifically triggered by `.pth` import lines that call `site.addsitedir()` during site startup.\n\n### CPython versions tested on:\n\n3.15\n\n### Operating systems tested on:\n\nmacOS\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-149516\n* gh-149659\n* gh-149799\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/JelleZijlstra","@type":"Person","name":"JelleZijlstra"},"datePublished":"2026-05-07T17:42:11.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":4},"url":"https://github.com/149504/cpython/issues/149504"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:5bf268f3-da15-8e4f-bf5e-0d1c3bfc461c |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B288:3E66CC:FFC206:16082B5:6A55D157 |
| html-safe-nonce | 7020e7787940f33912c6b599fa454f56b35053dfbff90b4aca8dfd6f4abbc7af |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCMjg4OjNFNjZDQzpGRkMyMDY6MTYwODJCNTo2QTU1RDE1NyIsInZpc2l0b3JfaWQiOiI2MTE5NjUwNzA0Mjg0MzA3Nzk5IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 135e5d90c412b39075a38694704403294bf39f2b68de99377017f89ed47cc42b |
| hovercard-subject-tag | issue:4400801061 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/149504/issue_layout |
| twitter:image | https://opengraph.githubassets.com/e883f06944d55864992d09f1ed751c9726a78c0e6e4e0a6df95b46f3619fafa7/python/cpython/issues/149504 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/e883f06944d55864992d09f1ed751c9726a78c0e6e4e0a6df95b46f3619fafa7/python/cpython/issues/149504 |
| og:image:alt | Bug report Bug description: I found a regression in Python 3.15’s site.py startup-file processing. A .pth file containing an import line that calls site.addsitedir() can re-enter process_startup_fi... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | JelleZijlstra |
| hostname | github.com |
| expected-hostname | github.com |
| None | b5665c84831ed9ac4fb79519c16c9c5580ba8092fb8bb6e3e72972ec7197348e |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 8f8e1726192df8dce16872ceb503336c12e9ae78 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width