Skip to content

python.asyncio.missing_timeout

Stability Medium

Detects async operations that should have timeouts but don’t, which can lead to tasks hanging indefinitely.

Async operations without timeouts can:

  • Hang indefinitely — A single stuck task can hold resources forever
  • Exhaust connection pools — Tasks waiting on unresponsive services never release connections
  • Cascade failures — One slow operation can block entire request pipelines
  • Prevent graceful shutdown — Untimed operations ignore cancellation signals
# ❌ Before (can wait forever)
import asyncio
async def main():
done, pending = await asyncio.wait(tasks)
async def get_from_queue(queue):
item = await queue.get() # Blocks forever if empty
# ✅ After (bounded waiting)
import asyncio
async def main():
done, pending = await asyncio.wait(tasks, timeout=30.0)
# Handle pending tasks
for task in pending:
task.cancel()
async def get_from_queue(queue):
try:
item = await asyncio.wait_for(queue.get(), timeout=30.0)
except asyncio.TimeoutError:
# Handle timeout
pass
  • asyncio.wait() without timeout parameter
  • asyncio.gather() without timeout wrapper
  • Queue.get() without timeout
  • Lock.acquire() without timeout
  • Very long asyncio.sleep() calls without cancellation support

Unfault generates patches that add appropriate timeout parameters to async operations:

# asyncio.wait with timeout
done, pending = await asyncio.wait(tasks, timeout=30.0)
# asyncio.gather with timeout wrapper (Python 3.11+)
async with asyncio.timeout(30.0):
results = await asyncio.gather(task1, task2, task3)