🚀 New issue to taskiq-python/taskiq by
@juanmicl
📝 Worker misparses positional arguments when a preceding parameter lacks a type annotation (#666)
Taskiq version
Taskiq version 0.12.6 (master)
Python version
Python 3.12
OS
Linux
What happened?
parse_params in taskiq/receiver/params_parser.py maps positional arguments to annotations with a counter (argnum) that only increments for annotated parameters. Unannotated parameters are skipped with continue before argnum += 1, but get_type_hints() omits them too, so they still occupy a slot in message.args. When any positional parameter has no annotation, every argument after it is parsed against the wrong annotation.
Example:
@broker.task
async def my_task(request_id, count: int) -> None: ...
await my_task.kiq("12345", 3)
What the worker receives (verified on master, taskiq 0.12.6):
1. request_id arrives as the int 12345. The unannotated parameter's value is coerced by the next parameter's annotation.
2. count is never validated. kiq("hello", "not-an-int") delivers "not-an-int" to count, and the only log line is a Can't parse argument 0 warning about the other parameter.
3. If the first value fails to parse, the annotated parameter after it never gets coerced either. It keeps its wire representation, so a datetime parameter receives an ISO string.
4. *values: int varargs coerce only the first element. kiq("1", "2", "3") arrives as [1, "2", "3"].
Standalone repro of the worker path, no broker needed:
import inspect
from typing import get_type_hints
from taskiq.formatters.json_formatter import JSONFormatter
from taskiq.message import TaskiqMessage
from taskiq.receiver.params_parser import parse_params
fmt = JSONFormatter()
def my_task(request_id, count: int) -> None: ...
msg = fmt.loads(fmt.dumps(TaskiqMessage(
task_id="1",
task_name="mod:my_task",
labels={},
labels_types={},
args=["12345", 3],
kwargs={},
)).message)
parse_params(inspect.signature(my_task), get_type_hints(my_task),