Unnormalized script_name causes worker replacement
Author: RogdhamCreated Aug 29, 2026Updated Aug 29, 2026
Description
A Monty worker is discarded from the pool when both of the following conditions apply:
- Type checking is enabled
script_namecontains unresolved..components (e.g.../../file.pyorfoo/../bar.py)
This is a performance issue (not a security issue): a new worker is created instead of the old one being reused.
The issue has been confirmed with pydantic-monty==0.0.21.
Minimal reproducible example
To illustrate, the code below forces the number of processes to 1, runs two sessions and displays their PIDs.
import asyncio
from pydantic_monty import AsyncMonty
async def main() -> None:
async with AsyncMonty(min_processes=1, max_processes=1) as pool:
async with pool.checkout(script_name="../../file.py", type_check=True) as session_a:
print('pid', session_a.worker_pid, '(session A)')
await session_a.feed_run("1 + 1")
async with pool.checkout() as session_b:
print('pid', session_b.worker_pid, '(session B)')
asyncio.run(main())Typical output (the two PIDs differ):
pid 172599 (session A)
pid 172601 (session B)Analysis
script_nameis accepted without normalization and used as a virtual path- Paths containing
..retain lexical parent components (e.g.../../file.py) - During cleanup, Monty compares each lexical ancestor with the exact root path
/ - The alias is not lexically equal to
/, so cleanup attempts to remove it and fails - The worker emits a fatal event and is discarded to prevent stale type-checking state from being reused
- The next checkout creates a replacement worker instead
Source: pydantic/monty