Python 3.8.1 removes unsafe UDP address reuse
asyncio stops supporting reuse_address for datagram endpoints because the UDP socket option can distribute incoming traffic across processes with different user IDs.
A socket option that sounds like a convenience for restarting a service can affect which process receives its traffic. Python 3.8.1 removes support for reuse_address on asyncio datagram endpoints because its UDP behavior can allow unrelated processes to receive incoming packets for the same address.
The December 18 release is the first maintenance release of Python 3.8. Its versioned release notes record the removal under bpo-37228. This is a security-motivated compatibility change inside a maintenance update, with consequences for callers that explicitly enabled the option.
The 3.8.1 event-loop documentation provides the reason. When processes with different user IDs bind sockets to the same UDP address using SO_REUSEADDR, incoming packets can become randomly distributed among those sockets. An option at endpoint creation therefore affects delivery ownership.
I prefer a library to reject a setting with that consequence instead of preserving a familiar call merely for compatibility. Python's networking abstractions are useful when they make the underlying contract manageable. A parameter whose practical effect can cross process identities needs a more precise explanation than its name supplies.
UDP reuse differs from a restart convenience
The documented problem concerns UDP datagram endpoints and SO_REUSEADDR. It should not be explained through assumptions about another socket type. A parameter with the same spelling can participate in different operating-system behavior depending on the socket operation.
For UDP, the concerning outcome is packet distribution across sockets assigned by processes with differing user IDs. That changes who receives data. The problem is therefore about the relationship between a local address and the process that owns the expected receiver, independently of whether the application can successfully create its socket.
Successful binding is insufficient evidence of the intended delivery policy. A program can establish an endpoint while the operating system's reuse rules allow another matching endpoint to exist. The Python change refuses a setting associated with that documented exposure.
This also explains why an apparently small configuration argument can justify a maintenance incompatibility. The argument changes a resource-sharing policy at the operating-system boundary. Keeping a permissive call shape would preserve a behavior the release now identifies as unsafe.
Explicit use now fails
The event-loop documentation says explicitly passing reuse_address=True raises an exception. Existing code that supplied the option can therefore fail while creating its datagram endpoint after an interpreter update. That failure is part of the corrected contract.
The relevant call is loop.create_datagram_endpoint(). It creates a datagram connection and returns a transport and protocol on success. Removing support for the reuse setting changes endpoint construction, before the application starts treating the returned transport as its communications interface.
A minimal endpoint construction can omit the removed setting.
import asyncio
class Receiver(asyncio.DatagramProtocol):
def datagram_received(self, data, address):
print(address, data)
async def receive():
loop = asyncio.get_running_loop()
transport, protocol = await loop.create_datagram_endpoint(
Receiver,
local_addr=("127.0.0.1", 9999),
)
try:
await asyncio.sleep(1)
finally:
transport.close()
asyncio.run(receive())
This example creates a local UDP receiver for a short interval. Omitting the option does not promise that all applications need the same address or lifetime. It shows that ordinary endpoint creation does not require explicitly requesting the removed behavior.
Port reuse has a different identity rule
The documentation names reuse_port as an alternative on platforms that support it. That option uses SO_REUSEPORT, with a rule that specifically prevents processes with differing user IDs from assigning sockets to the same address. The difference directly addresses the identity condition described in the security note.
It is therefore inaccurate to describe the replacement as merely another spelling for the same operation. The options request different kernel behavior. A program intentionally sharing datagram traffic needs to choose according to the sharing policy it requires and the facilities its platform supplies.
The platform qualification matters as well. The release documentation does not promise that reuse_port works everywhere. Removing one unsupported or unsafe request does not establish that another option is universally available. An application's endpoint policy needs to be compatible with its actual operating-system support.
My interest is in that explicit distinction between creating a socket and deciding who may share its address. An asynchronous transport hides much of the event handling, but the delivery policy still comes from the socket configuration. The library documentation now explains why these two reuse settings cannot be treated interchangeably.
Maintenance also extends audit coverage
The same release notes record additional audit events for ctypes and corrections around existing event names. The os.system event receives its expected name, while replacing a code object raises the code.__new__ event. These changes concern runtime observation, separately from the datagram configuration correction.
That work is relevant to integrations relying on Python 3.8's new auditing mechanism. Having a hook API and having an event at a particular operation are different requirements. The maintenance release adds or corrects coverage at named operations without implying that all runtime activity produces an event.
Python 3.8.1 thus changes a concrete networking contract alongside ordinary maintenance work. Explicit UDP address reuse through the affected asyncio option now fails, while supported port reuse has a documented user-ID restriction. Applications constructing datagram endpoints can reason about the option through the packet-delivery policy it requests.