nautechsystems/nautilus_trader · error · ValueError

Chart renderer must be callable, was {type(renderer)}

Error message

Chart renderer must be callable, was {type(renderer)}

What it means

register_tearsheet_chart validates that the renderer argument is callable; anything else (a called result, a None default, an object) is rejected with the offending type in the message. The renderer is later invoked as renderer(fig=..., row=..., col=..., **kwargs) during figure assembly, so a non-callable would fail much later and less clearly.

Source

Thrown at python/nautilus_trader/analysis/tearsheet.py:2468

        Display title for the subplot.
    renderer : Callable
        Function that adds traces to the figure. Signature:
        renderer(fig, row, col, returns, stats_pnls, stats_returns, stats_general,
        theme_config, benchmark_returns, benchmark_name, run_info, account_info, engine, **kwargs)

    Raises
    ------
    ValueError
        If name is empty or renderer is not callable.

    """
    _require_not_none(name, "name")

    if not name.strip():
        raise ValueError("Chart name cannot be empty")

    if not callable(renderer):
        raise ValueError(f"Chart renderer must be callable, was {type(renderer)}")

    _TEARSHEET_CHART_SPECS[name] = {
        "type": subplot_type,
        "title": title,
        "renderer": renderer,
    }


def _calculate_grid_layout(
    charts: list[TearsheetChart],
    custom_layout: Any = None,
) -> tuple[int, int, list, list[str], list[float], float, float]:
    """
    Calculate dynamic grid layout based on selected charts.

    Parameters
    ----------
    charts : list[TearsheetChart]

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Pass the function object itself: register_tearsheet_chart('x', 'xy', 'T', render_chart) with no parentheses
  2. If wrapping an instance, give the class a __call__ method or pass a lambda closing over it
  3. Confirm with callable(renderer) before registering

Example fix

# before
register_tearsheet_chart(name='c', subplot_type='xy', title='T', renderer=render_chart())
# ValueError: Chart renderer must be callable, was Figure

# after
register_tearsheet_chart(name='c', subplot_type='xy', title='T', renderer=render_chart)
Defensive patterns

Strategy: type-guard

Validate before calling

if not callable(renderer):
    raise TypeError(f'renderer must be callable, got {type(renderer).__name__}')
register_tearsheet_chart(name, 'xy', title, renderer)

Type guard

from typing import Callable

def is_renderer(obj: object) -> bool:
    return callable(obj)

Try / catch

try:
    register_tearsheet_chart(name, 'xy', title, renderer)
except ValueError as e:
    raise TypeError('Pass the function itself, not its result') from e

Prevention

When it happens

Trigger: Passing renderer=render_chart() (calling the function, yielding its return value) instead of renderer=render_chart; passing a class instance without __call__; passing None or a string.

Common situations: Decorators/call-results mistaken for functions; wrapper objects that forgot __call__; copy-paste from an example where parentheses were added.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/37a231d6178f7985. Report an issue: GitHub.