Azure / Azure/azure-functions-python-worker
[Python 3.14 proxy worker] Missing sys.modules["__main__"] breaks multiprocessing spawn
- Dominant language
- Python
- Stars
- 357
- Forks
- 116
- Avg merge
- 32m
- Merged PRs (30d)
- 1
Description
### Description
The Azure Functions Python 3.14 proxy worker removes `__main__` from
`sys.modules` before invoking application code.
As a result, Python's standard `multiprocessing` spawn context fails during
`Process.start()`, before the child process or its target function begins
executing.
This is not specific to any third-party package. The minimal reproduction uses
only `azure-functions` and the Python standard library.
### Environment
- Azure Functions Python runtime: 3.14
- Python: 3.14.6
- Azure Functions Core Tools: 4.12.0
- Functions runtime: 4.1048.200.26180
- Programming model: Python v2
- `azure-functions` application package: 2.2.0
- Reproduced locally inside the Functions worker
- The same failure was observed after deploying the application to Azure Functions on Python 3.14
The same application code worked on the Python 3.12 Functions runtime.
### Minimal reproduction
```python
import multiprocessing
import sys
import azure.functions as func
app = func.FunctionApp()
def child_process() -> None:
return None
@app.route(route="multiprocessing-repro")
def multiprocessing_repro(req: func.HttpRequest) -> func.HttpResponse:
main_present = "__main__" in sys.modules
context = multiprocessing.get_context("spawn")
process = context.Process(target=child_process)
process.start()
process.join()
return func.HttpResponse(
f"__main__ present: {main_present}; exit code: {process.exitcode}"
)
```
Start the application using Core Tools with Python 3.14 and invoke
`/api/multiprocessing-repro`.
### Actual behavior
`"__main__" in sys.modules` is false during the function invocation, and
`Process.start()` raises:
```text
Traceback (most recent call last):
File ".../multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
File ".../multiprocessing/context.py", line 289, in _Popen
return Popen(process_obj)
File ".../multiprocessing/popen_spawn_posix.py", line 32, in __init__
super().__init__(process_obj)
File ".../multiprocessing/popen_fork.py", line 19, in __init__
self._launch(process_obj)
File ".../multiprocessing/popen_spawn_posix.py", line 42, in _launch
prep_data = spawn.get_preparation_data(process_obj._name)
File ".../multiprocessing/spawn.py", line 164, in get_preparation_data
main_module = sys.modules["__main__"]
KeyError: "__main__"
```
The failure occurs before the child process starts.
### Expected behavior
The Functions worker should retain a valid `__main__` module, or otherwise
initialize the application environment so that standard-library
`multiprocessing` spawn works inside a function invocation.
### Investigation
The Python 3.14 worker uses `proxy_worker`. Its dependency cleanup appears to
remove modules from `sys.modules` based on their file location. It excludes
modules whose names begin with `proxy_worker`, but does not appear to exclude
`__main__`.
That appears to leave the invocation environment without the module required
by `multiprocessing.spawn.get_preparation_data()`.
Launching an explicit Python subprocess with an importable module works in the
same Functions-host process, confirming that the failure is specifically in
the `multiprocessing` spawn preparation path.
### Impact
Any application or dependency that uses the standard-library spawn context can
fail under the Python 3.14 Functions worker. In our application this prevented
all isolated document conversions from starting, regardless of document type.
### Related issue
Related historical issue: #1094 reported the same missing-`__main__` worker
condition on Python 3.9 through a different caller.
This report concerns the Python 3.14 proxy worker and reproduces through:
```python
multiprocessing.get_context("spawn").Process(...).start()
```
It is therefore related behavior, but not the same caller or worker
implementation.
Contributor guide
Assessment
This issue has not been assessed yet.