locustio/locust · error · NonMarkovTaskTransitionError
{classname}.{dest} cannot be used as a target for a transiti
Error message
{classname}.{dest} cannot be used as a target for a transition since it does not define any transitions of its own.Used as a transition from {task.__name__}. What it means
A Markov transition target must itself be a Markov task, i.e. it must declare its own transitions. Pointing a transition at a plain @task without transitions breaks the chain (the walk could reach a dead end), so NonMarkovTaskTransitionError is raised.
Source
Thrown at locust/user/markov_taskset.py:180
This function checks two conditions for each transition:
1. The target task exists in the class
2. The target task is also a Markov task (has transitions defined)
:param tasks: List of Markov tasks to validate
:param class_dict: Dictionary containing class attributes and methods
:param classname: Name of the class being validated (for error messages)
:raises InvalidTransitionError: If a transition points to a non-existent task
:raises NonMarkovTaskTransitionError: If a transition points to a task that isn't a Markov task
"""
for task in tasks:
for dest in task.transitions.keys():
dest_task = class_dict.get(dest)
if not dest_task:
raise InvalidTransitionError(
f"Transition to {dest} from {task.__name__} is invalid since no such element exists on class {classname}"
)
if not is_markov_task(dest_task):
raise NonMarkovTaskTransitionError(
f"{classname}.{dest} cannot be used as a target for a transition since it does not define any transitions of its own."
+ f"Used as a transition from {task.__name__}."
)
def validate_no_unreachable_tasks(tasks: list, class_dict: dict, classname: str):
"""
Checks for and warns about unreachable Markov tasks in a MarkovTaskSet.
This function uses depth-first search (DFS) starting from the first task to identify
all reachable tasks. It then warns about any tasks that cannot be reached from the
starting task through the defined transitions.
:param tasks: List of Markov tasks to validate
:param class_dict: Dictionary containing class attributes and methods
:param classname: Name of the class being validated (for warning messages)
:return: The original list of tasks
"""View on GitHub (pinned to f391a716e1)
Solutions
- Give the target task at least one @transition (e.g. back to itself or to another task) so it qualifies as a Markov task
- If the state should be terminal, transition it to itself with a weight, or restructure the chain so it isn't a transition target
- Verify every @transition destination uses @task together with @transition/@transition_all
Example fix
// before
@task
def done(self):
self.client.get("/done")
// after
@task
@transition(MyUser.done) # loop back or point to another state
def done(self):
self.client.get("/done") Defensive patterns
Strategy: validation
Validate before calling
for t in MyUser.__dict__.values():
for dest in getattr(t, "transitions", {}):
assert getattr(MyUser.__dict__.get(dest), "transitions", None), f"{dest} is not a Markov task" Try / catch
try:
validate_markov_chain(tasks, dict(vars(MyUser)), MyUser.__name__)
except NonMarkovTaskTransitionError as e:
logging.error(e)
raise Prevention
- Give every transition-reachable task its own @transition
- Model terminal states as self-transitions
- Validate chains in unit tests before running load tests
When it happens
Trigger: @transition(MyUser.final_step) where final_step is a @task with no @transition decorators of its own; adding a new terminal task and using it as a target from another task.
Common situations: Modeling a 'done/end' state as a plain task; forgetting that every reachable state in a Markov chain must define outgoing transitions; converting a plain TaskSet where last methods had no transitions.
Related errors
- Transition to {dest} from {task.__name__} is invalid since n
- No Markov tasks defined in class {classname}. Use the @trans
- Tags are unsupported for MarkovTaskSet since they can make t
- TaskSet.run() is a method used internally by Locust, and you
- In order to use a with-block for requests, you must also pas
AI-assisted analysis of locustio/locust@f391a716e1 (2026-08-29).
Data as JSON: /api/errors/662352b4392b512f.
Report an issue: GitHub.