2026, Jan 06 23:00

Explicitly return None to satisfy mypy: handling implicit returns in Python functions

Learn how to fix mypy Missing return errors in Python by making implicit None explicit. Clear examples, reasons, and alternatives for clean static typing.

When you annotate a function to return a value in Python, static typing tools like mypy expect every control-flow path to end with a concrete return. Relying on Python’s implicit None can look perfectly fine at runtime, yet still trigger type-checker errors. Here’s how to address it cleanly and why it matters for readable, maintainable code.

Minimal example of the issue

The pattern below tries something, returns a result on success, and otherwise falls back to None implicitly:

def pick_value(flag: bool) -> int | None:
    if flag:
        return 1
def derive_value(flag: bool) -> int | None:
    if flag:
        return
    return 1

Although this is valid Python, mypy reports:

1: error: Missing return statement  [return]
7: error: Return value expected  [return-value]

What’s going on

Python implicitly returns None when a function ends without an explicit return. In the first function above, the branch where flag is False reaches the end without a return; in the second, there’s a bare return inside a function that advertises int | None. Mypy flags both cases because the function signatures promise a return value in every path, and the checker requires you to be explicit about that value. The tool is nudging you to make the control flow obvious, not inferred.

The fix: return None explicitly

Make the None path explicit in both functions. This preserves the existing runtime semantics but satisfies the type checker and clarifies intent for readers of the code.

def pick_value(flag: bool) -> int | None:
    if flag:
        return 1
    return None
def derive_value(flag: bool) -> int | None:
    if flag:
        return None
    return 1

This version is type-checker friendly and easier to read: every branch makes the return value explicit.

If you must silence mypy without changing logic

You can turn off the specific “missing return” warning for the entire codebase using the --no-warn-no-return option. If you prefer a local, line-level suppression, add targeted ignores where the diagnostics are raised:

def pick_value(flag: bool) -> int | None:  # type: ignore[return]
    if flag:
        return 1
def derive_value(flag: bool) -> int | None:
    if flag:
        return  # type: ignore[return-value]
    return 1

However, it’s typically less effort—and more communicative—to return None explicitly rather than carry ignore markers.

Why this is worth knowing

Clear return paths reduce cognitive load in reviews and maintenance. It’s customary in Python that if a function is expected to return a value, it should do so explicitly in every case. The implicit return is mainly useful in procedures, where no value is expected. Style guidance also discourages bare returns in favor of returning None explicitly.

Any return statements where no value is returned should explicitly state this as return None.

Takeaways

When a function advertises a return type like int | None, make every branch explicit: return a value on success and return None otherwise. This aligns with mypy’s diagnostics, keeps the control flow self-evident, and follows common Python style. If you can’t touch the code, you can suppress mypy with --no-warn-no-return or targeted type: ignore comments, but the explicit None is the most readable and maintainable route.