Skip to content

RuntimeWarning: coroutine 'LLMService._run_function_call.<locals>.timeout_handler' was never awaited when function call triggers pipeline end #3588

@mhussam-ai

Description

@mhussam-ai

pipecat version

v0.0.100 (Unreleased)

Python version

3.12

Operating System

Linux (Docker/Kubernetes on AKS)

Issue description

When using GeminiLiveLLMService (or GeminiLiveVertexLLMService) with a registered function that ends the pipeline (like end_call), a RuntimeWarning is logged because the timeout handler coroutine is never awaited.

Analysis:

The issue appears to be a race condition in LLMService._run_function_call(). When the function call (e.g., end_call) triggers pipeline shutdown via EndTaskFrame/EndFrame, the timeout handler coroutine created for that function call is orphaned before it can be properly cancelled or awaited.

Potential Fix:

The timeout handler task should be properly cancelled in a finally block or when the function call completes, ensuring it doesn't get garbage collected with an unawaited coroutine.

Workaround:

The warning is cosmetic and doesn't affect functionality. Calls complete successfully.

Potential Code Fix:

File: pipecat/services/llm_service.py
Method: _run_function_call() (lines 577-672)

The Bug (Lines 604-612, 669-672)

# Line 612: timeout_task is created
timeout_task = self.create_task(timeout_handler())
# ... handler is called ...
except Exception as e:
    # Line 669-672: No finally block!
    error_message = f"Error executing function call [...]"
    logger.error(...)
    await self.push_error(...)
# Function ends WITHOUT cancelling timeout_task if:
# 1. Handler doesn't call result_callback (rare edge case)
# 2. Exception is raised (timeout_task leaks)
# 3. Handler triggers pipeline end (end_call case)

The Fix

Add a finally block to ensure timeout_task is always cancelled:

# After line 668, add:
        except Exception as e:
            error_message = f"Error executing function call [{runner_item.function_name}]: {e}"
            logger.error(f"{self} {error_message}")
            await self.push_error(error_msg=error_message, exception=e, fatal=False)
        finally:
            # Ensure timeout task is cancelled to prevent "coroutine never awaited" warning
            if timeout_task and not timeout_task.done():
                await self.cancel_task(timeout_task)

Why This Fixes It

When end_call triggers EndTaskFrame/EndFrame:

  1. The handler completes (or the pipeline starts shutting down)
  2. The _run_function_call method exits
  3. Without the fix: timeout_task is orphaned → RuntimeWarning
  4. With the fix: finally block cancels timeout_task cleanly

Reproduction steps

  1. Register an end_call function that pushes EndTaskFrame and EndFrame to gracefully end the call
  2. During a conversation, trigger the function call (e.g., user says goodbye, LLM invokes end_call)
  3. Observe the warning in logs

Expected behavior

No warnings - the timeout handler should be properly cancelled or awaited when the pipeline ends.

Actual behavior

/usr/local/lib/python3.12/asyncio/events.py:88: RuntimeWarning: coroutine 'LLMService._run_function_call..timeout_handler' was never awaited
self._context.run(self._callback, *self._args)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Logs

2026-01-29 11:17:05.015 | DEBUG | pipecat.observers.loggers.llm_log_observer:on_push_frame:68 - 🧠 GeminiLiveVertexLLMService#5 → LLM GENERATING: ' Bye!' at 114.21s
/usr/local/lib/python3.12/asyncio/events.py:88: RuntimeWarning: coroutine 'LLMService._run_function_call.<locals>.timeout_handler' was never awaited
  self._context.run(self._callback, *self._args)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
2026-01-29 11:17:05.170 | DEBUG | pipecat.services.llm_service:_run_function_call:585 - GeminiLiveVertexLLMService#5 Calling function [end_call:...] with arguments {'reason': 'conversation concluded.'}
2026-01-29 11:17:05.170 | INFO | bots.base_bot:end_call:313 - end_call triggered for Mohammad Hussam (08767872521). Reason: conversation concluded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions