From 9512562e134eb5ff728a14cdd33d53346d59bcfe Mon Sep 17 00:00:00 2001 From: sinnercode228 Date: Fri, 2 Oct 2026 06:09:51 +0700 Subject: [PATCH] fix: do not parse return value of errored tasks When a task fails, the receiver stores a result with `is_err=True` and `return_value=None`. `AsyncTaskiqTask.get_result` still tried to validate that `None` against the task's return annotation, so every failed task with a non-optional return type logged a misleading "Cannot parse return type into ..." warning on the client side. Skip the validation when the result is an error: there is no return value to parse, and the actual failure is already available in `result.error`. Closes: #479 --- taskiq/task.py | 4 +++- tests/test_task.py | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/taskiq/task.py b/taskiq/task.py index 550dabee..ce057900 100644 --- a/taskiq/task.py +++ b/taskiq/task.py @@ -61,7 +61,9 @@ async def get_result(self, with_logs: bool = False) -> "TaskiqResult[_ReturnType self.task_id, with_logs=with_logs, ) - if self.return_type is not None: + # Errored tasks have no return value to validate, + # so parsing would only produce a misleading warning. + if self.return_type is not None and not res.is_err: try: res.return_value = parse_obj_as( self.return_type, diff --git a/tests/test_task.py b/tests/test_task.py index 8d239280..820425d6 100644 --- a/tests/test_task.py +++ b/tests/test_task.py @@ -1,5 +1,6 @@ +import logging import uuid -from typing import TypeVar +from typing import Any, TypeVar import pytest from pydantic import BaseModel @@ -68,3 +69,41 @@ class MyResult(BaseModel): sent_task = AsyncTaskiqTask(test_id, res_back, MyResult) parsed = await sent_task.wait_result() assert isinstance(parsed.return_value, MyResult) + + +async def test_res_parsing_skipped_on_error(caplog: pytest.LogCaptureFixture) -> None: + res_back: AsyncResultBackend[Any] = SerializingBackend(serializers.JSONSerializer()) + test_id = str(uuid.uuid4()) + await res_back.set_result( + test_id, + TaskiqResult( + is_err=True, + return_value=None, + execution_time=0.0, + ), + ) + sent_task: AsyncTaskiqTask[Any] = AsyncTaskiqTask(test_id, res_back, int) + with caplog.at_level(logging.WARNING, logger="taskiq.task"): + parsed = await sent_task.wait_result() + assert parsed.is_err + assert parsed.return_value is None + assert "Cannot parse return type" not in caplog.text + + +async def test_res_parsing_failure(caplog: pytest.LogCaptureFixture) -> None: + res_back: AsyncResultBackend[Any] = SerializingBackend(serializers.JSONSerializer()) + test_id = str(uuid.uuid4()) + await res_back.set_result( + test_id, + TaskiqResult( + is_err=False, + return_value="not-an-int", + execution_time=0.0, + ), + ) + sent_task: AsyncTaskiqTask[Any] = AsyncTaskiqTask(test_id, res_back, int) + with caplog.at_level(logging.WARNING, logger="taskiq.task"): + parsed = await sent_task.wait_result() + assert not parsed.is_err + assert parsed.return_value == "not-an-int" + assert "Cannot parse return type" in caplog.text