locustio/locust · error · ValueError
The 'tasks' attribute can only be set to list or dict
Error message
The 'tasks' attribute can only be set to list or dict
What it means
SequentialTaskSet.__new__ expands the 'tasks' attribute into an ordered list. Only lists (and methods decorated with @task) are allowed for sequential execution; other types raise ValueError. Notably, unlike TaskSet, a plain dict of task->weight is rejected here even though the expansion code path handles nested dicts inside lists.
Source
Thrown at locust/user/sequential_taskset.py:34
def __new__(mcs, classname, bases, class_dict):
new_tasks = []
for base in bases:
# first get tasks from base classes
if hasattr(base, "tasks") and base.tasks:
new_tasks += base.tasks
for key, value in class_dict.items():
if key == "tasks":
# we want to insert tasks from the tasks attribute at the point of it's declaration
# compared to methods declared with @task
if isinstance(value, list):
new_tasks.extend(value)
elif isinstance(value, dict):
for task, weight in value.items():
for _ in range(weight):
new_tasks.append(task)
else:
raise ValueError("The 'tasks' attribute can only be set to list or dict")
if "locust_task_weight" in dir(value):
# method decorated with @task
for _ in range(value.locust_task_weight):
new_tasks.append(value)
class_dict["tasks"] = new_tasks
return type.__new__(mcs, classname, bases, class_dict)
class SequentialTaskSet(TaskSet, metaclass=SequentialTaskSetMeta):
"""
Class defining a sequence of tasks that a User will execute.
Works like TaskSet, but task weight is ignored, and all tasks are executed in order. Tasks can
either be specified by setting the *tasks* attribute to a list of tasks, or by declaring tasks
as methods using the @task decorator. The order of declaration decides the order of execution.
View on GitHub (pinned to f391a716e1)
Solutions
- Set 'tasks' to a list; express repetition by duplicating entries, e.g. [TaskA, TaskA, TaskA] instead of {TaskA: 3}
- Wrap weighted dicts inside a plain TaskSet instead, or build the list programmatically
- Ensure dynamically built tasks are converted with list(...) before assignment
Example fix
// before
class MyFlow(SequentialTaskSet):
tasks = {TaskA: 3, TaskB: 1}
// after
class MyFlow(SequentialTaskSet):
tasks = [TaskA, TaskA, TaskA, TaskB] Defensive patterns
Strategy: type-guard
Validate before calling
tasks = getattr(MyFlow, "tasks", [])
if not isinstance(tasks, list):
raise TypeError("SequentialTaskSet.tasks must be a list") Type guard
def has_valid_tasks(cls) -> bool:
tasks = getattr(cls, "tasks", None)
return isinstance(tasks, list) and len(tasks) > 0 Try / catch
try:
flow = MyFlow(user)
except ValueError as e:
if "tasks" in str(e):
logging.error("Convert tasks to a list")
raise Prevention
- Remember SequentialTaskSet accepts lists only, not weighted dicts
- Expand weights manually into repeated list entries
- Add a class-level assertion in custom SequentialTaskSet base classes
When it happens
Trigger: Setting tasks = {TaskA: 3} (a dict) on a SequentialTaskSet subclass, or assigning tasks to a non-list value like a single callable or tuple of unsupported items.
Common situations: Copying the dict-based weighted tasks pattern from TaskSet docs into SequentialTaskSet; passing a tuple instead of a list; dynamic task assembly that produces a set or generator.
Related errors
- No tasks defined. Use the @task decorator or set the 'tasks'
- No Markov tasks defined in class {classname}. Use the @trans
- In order to use a with-block for requests, you must also pas
- Tried to set status on a request that has not yet been made.
- If you want to change the state of the request using .succes
AI-assisted analysis of locustio/locust@f391a716e1 (2026-08-29).
Data as JSON: /api/errors/83bf561b86dafca1.
Report an issue: GitHub.