HKUDS/Vibe-Trading · error · LiveRunnerUnavailable

live runner for {broker!r} does not define remote tool {oper

Error message

live runner for {broker!r} does not define remote tool {operation!r}

What it means

Raised by LiveRunnerUnavailable when the helper _tool() cannot map a broker's operation (e.g. 'positions' or 'account') to a remote tool name via runner_tool_name(broker, operation). This happens during _build_live_runner, meaning the selected broker's live runner contract has no registered tool for that operation — typically a registration/mapping gap in src/trading/service.py or an unsupported broker slipped through earlier validation.

Source

Thrown at agent/src/api/live_routes.py:554

    """
    h = _host()

    # _runner_factory is monkeypatched on host by tests
    factory = getattr(h, "_runner_factory", None)
    if factory is not None:
        return factory(broker)

    from src.live.audit import write_live_action
    from src.live.runtime.reconcile import reconcile
    from src.live.runtime.runner import LiveRunner
    from src.live.runtime.scheduler import Scheduler
    from src.live.runtime.triggers import Trigger
    from src.trading.service import runner_tool_name

    def _tool(operation: str) -> str:
        remote_tool = runner_tool_name(broker, operation)
        if remote_tool is None:
            raise LiveRunnerUnavailable(
                f"live runner for {broker!r} does not define remote tool {operation!r}"
            )
        return remote_tool

    positions_tool = _tool("positions")
    balance_tool = _tool("account")
    open_orders_tool = _tool("orders")
    submit_order_tool = _tool("submit_order")
    cancel_order_tool = _tool("cancel_order")

    # _live_broker_adapter is monkeypatched on host by tests
    adapter = h._live_broker_adapter(broker)

    def _read(remote_tool: str):
        return lambda: adapter.call_tool(remote_tool, {})

    def _submit(order: Dict[str, Any]) -> Dict[str, Any]:
        if order.get("action") == "cancel":

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Check runner_tool_name in src/trading/service.py and confirm the broker/operation pair is registered
  2. Add the missing mapping entry for the broker's 'positions' and 'account' tools
  3. If the broker genuinely lacks an operation, gate the endpoint earlier with a 400 'not supported' instead of building the runner
  4. Retry after upgrading/redeploying so agent and runner versions match

Example fix

// before (src/trading/service.py)
RUNNER_TOOLS = {"ibkr": {"positions": "ibkr_positions", "account": "ibkr_account"}}

// after
RUNNER_TOOLS = {
    "ibkr": {"positions": "ibkr_positions", "account": "ibkr_account"},
    "tradier": {"positions": "tradier_positions", "account": "tradier_balances"},
}
Defensive patterns

Strategy: validation

Validate before calling

from src.trading.service import runner_tool_name

def can_build_runner(broker: str, ops=("positions", "account")) -> bool:
    return all(runner_tool_name(broker, op) is not None for op in ops)

Type guard

def has_runner_tools(broker: str) -> bool:
    from src.trading.service import runner_tool_name
    return runner_tool_name(broker, 'positions') is not None and runner_tool_name(broker, 'account') is not None

Try / catch

try:
    runner = _build_live_runner(broker)
except LiveRunnerUnavailable as e:
    logger.warning('runner tools missing for %s: %s', broker, e)
    return JSONResponse(status_code=501, content={'detail': str(e)})

Prevention

When it happens

Trigger: Calling any live endpoint that builds a live runner for a broker whose runner_tool_name(broker, 'positions') or (broker, 'account') returns None — e.g. GET /live/status?broker=<new-broker> after adding a broker connector without registering its remote tool names.

Common situations: Adding a new broker's live runner but forgetting to add its tool-name mapping; renaming operations in the runner registry without updating runner_tool_name; version skew between the agent API and the runner definitions.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/39fd9e12f9a21a73. Report an issue: GitHub.