locustio/locust · error · RunnerAlreadyExistsError

Environment.runner already exists ({self.runner})

Error message

Environment.runner already exists ({self.runner})

What it means

Environment allows only one runner per instance. `_create_runner` raises RunnerAlreadyExistsError if `self.runner` is already set before assigning a new runner of the given class (local, master, or worker).

Source

Thrown at locust/env.py:123

        self.available_user_tasks = available_user_tasks
        """List of the available Tasks per User Classes to pick from in the Task Picker"""
        self.dispatcher_class = dispatcher_class
        """A user dispatcher class that decides how users are spawned, default :class:`UsersDispatcher <locust.dispatch.UsersDispatcher>`"""
        self.worker_logs: dict[str, list[str]] = {}
        """Captured logs from all connected workers"""

        self._remove_user_classes_with_weight_zero()
        self._validate_user_class_name_uniqueness()
        self._validate_shape_class_instance()

    def _create_runner(
        self,
        runner_class: type[RunnerType],
        *args,
        **kwargs,
    ) -> RunnerType:
        if self.runner is not None:
            raise RunnerAlreadyExistsError(f"Environment.runner already exists ({self.runner})")
        self.runner = runner_class(self, *args, **kwargs)

        # Attach the runner to the shape class so that the shape class can access user count state
        if self.shape_class:
            self.shape_class.runner = self.runner

        return self.runner

    def create_local_runner(self) -> LocalRunner:
        """
        Create a :class:`LocalRunner <locust.runners.LocalRunner>` instance for this Environment
        """
        return self._create_runner(LocalRunner)

    def create_master_runner(self, master_bind_host="*", master_bind_port=5557) -> MasterRunner:
        """
        Create a :class:`MasterRunner <locust.runners.MasterRunner>` instance for this Environment

View on GitHub (pinned to f391a716e1)

Solutions

  1. Create a fresh Environment for each runner you need
  2. Guard with `if environment.runner is None:` before calling create_*_runner
  3. Call `environment.runner.stop()` / discard the old Environment instead of re-creating the runner
  4. In tests, move Environment construction into a pytest fixture with function scope

Example fix

// before
env.create_local_runner()
env.create_local_runner()  # raises
// after
if env.runner is None:
    env.create_local_runner()
Defensive patterns

Strategy: validation

Validate before calling

if env.runner is None:
    env.create_local_runner()
else:
    env.runner.stop()  # or create a new Environment

Type guard

def runner_is_free(env) -> bool:
    return env.runner is None

Try / catch

from locust.exception import RunnerAlreadyExistsError
try:
    env.create_local_runner()
except RunnerAlreadyExistsError:
    env.runner.stop()
    env.runner = None
    env.create_local_runner()

Prevention

When it happens

Trigger: Calling create_local_runner() twice on the same Environment; calling create_local_runner() after create_master_runner(); reusing a cached Environment object across test launches.

Common situations: Test harnesses that build one Environment fixture and start multiple runs; scripts that retry runner creation after a failed start without discarding the Environment; framework code that initializes a runner automatically then user code calls create_*_runner again.

Related errors


AI-assisted analysis of locustio/locust@f391a716e1 (2026-08-29). Data as JSON: /api/errors/087b2794a4d089af. Report an issue: GitHub.