This rule raises an issue when a function returns tuples of different lengths in different code paths.

Why is this an issue?

When a function returns tuples of varying lengths, it creates an inconsistent API that is difficult to use correctly. Callers cannot reliably unpack the return value without checking its length first, which leads to fragile code.

Consider this example:

def process_data(value):
    if value > 0:
        return (value,)  # Returns a 1-tuple
    else:
        return (value, value * 2)  # Returns a 2-tuple

# Caller has no reliable way to unpack this
result = process_data(10)
x, y = result  # ValueError if value > 0!

This forces callers to add defensive length-checks before unpacking, making the code fragile and harder to maintain. The function signature provides no indication that the return type varies, so developers must read the implementation or discover the behavior through runtime errors.

Consistent return types make code more predictable, easier to test, and less likely to cause unexpected failures in production.

What is the potential impact?

Runtime errors from tuple unpacking may not surface during initial testing if certain code paths are not fully exercised, leading to production failures. The need for defensive length-checking also increases the maintenance burden and makes the API harder to document for new team members.

How to fix it

Make all return statements return tuples of the same length. Add placeholder values (like None or 0) to shorter tuples to maintain consistency.

Code examples

Noncompliant code example

def calculate_stats(numbers):
    if not numbers:
        return (0,)  # Noncompliant
    total = sum(numbers)
    average = total / len(numbers)
    return (total, average)

Compliant solution

def calculate_stats(numbers):
    if not numbers:
        return (0, 0)  # Consistent 2-tuple
    total = sum(numbers)
    average = total / len(numbers)
    return (total, average)

Going the extra mile

For complex return types, consider using typing.NamedTuple to make the return value self-documenting. Named tuples provide clear field names and enforce a consistent structure, making the API easier to use and understand.

from typing import NamedTuple

class Stats(NamedTuple):
    total: float
    average: float

def calculate_stats(numbers) -> Stats:
    if not numbers:
        return Stats(total=0, average=0)
    total = sum(numbers)
    average = total / len(numbers)
    return Stats(total=total, average=average)

Resources

Documentation