Multiprocessing fails in __main__.py when using forkserver start method

I had some issues with updating to python 3.14 and using ProcessPool and narrowed down to the following minimal reproducer:

$ cat mypackage/__main__.py 
from multiprocessing import set_start_method, Process

def hello():
    print("hello")

if __name__ == '__main__':
    # set_start_method('fork')       # this works and prints hello (default in python 3.13)
    # set_start_method('forkserver') # this fails with `AttributeError: module '__main__' has no attribute 'hello'` (default in python 3.14)
    p = Process(target=hello)
    p.start()
    p.join()
$ python3 -m mypackage
Traceback (most recent call last):
  File "/usr/local/lib/python3.14/multiprocessing/forkserver.py", line 340, in main
    code = _serve_one(child_r, fds,
                      unused_fds,
                      old_handlers)
  File "/usr/local/lib/python3.14/multiprocessing/forkserver.py", line 380, in _serve_one
    code = spawn._main(child_r, parent_sentinel)
  File "/usr/local/lib/python3.14/multiprocessing/spawn.py", line 132, in _main
    self = reduction.pickle.load(from_parent)
AttributeError: module '__main__' has no attribute 'hello'

However this works:

  • if I run it as a script python3 mypackage/__main__.py

  • if I copy __main__.py to mymain.py and run like this: python3 -m mypackage.mymain

Funny enough python3 -m mypackage.__main__ doesn’t work! Is it some kind of a known issue? It seems odd to me that it only happens if the module name is __main__.

I did a bit of a search, and there are a bunch of similar issues where people are struggling to use multiprocessing in a REPL, but it my case it’s not in a repl.

Perhaps the closest relevant issue is this – but it seems to be impacting 3.13 only, whereas in this case issue happens on 3.14 as well.

Environment:

  • I ran it in a fresh docker container docker run --rm -it python:3.14 /bin/bash to make sure no other things impact this
  • python3 -V: Python 3.14.2
  • uname -a : `Linux … 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux`

The module named __main__.py is intentionally treated differently:

Use a different name.

3 Likes

Aah thanks, I should have guessed to just grep in cpython source code, this explains it at least.
Not 100% sure why it changed with forkserver, but seems like a deliberate choice, so not gonna dig it further.
Perhaps it’s worth updating documentation on multiprocessing — Process-based parallelism — Python 3.14.2 documentation ? Since it doesn’t mention this anywhere, and the error is quite cryptic.

That is explained: multiprocessing — Process-based parallelism — Python 3.14.2 documentation

Make a PR.

Note that this has been the case for decades and code that worked like this was never portable because windows can’t use fork, so always used spawn.

1 Like

I guess I also hadn’t realized I was using __main__.py in a non-idiomatic way – the suggestion is not to guard it with if __name__ == "__main__" , and then the advice from the existing multiprocessing documentation does apply.