#798·monty

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_name contains unresolved .. components (e.g. ../../file.py or foo/../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.

python
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_name is 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