Skip to content

bug: orderbook refresh thread crashes silently when API fetch fails #87

Description

@skyc1e

The background orderbook refresh thread in OrderBookManager._thread_refresh_order_book crashes permanently if _run_get_orders() returns None (e.g. API timeout or 429).

Root cause

_run_get_orders() catches exceptions and returns None on failure (line 333). The state update correctly guards with if orders is not None (line 377). But the debug log immediately after does not:

# orderbook.py, line 388-392
self.logger.debug(
    f"Fetched the order book"
    f" (orders: {[order.id for order in orders]}, "  # TypeError if orders is None
    ...
)

This throws TypeError: 'NoneType' object is not iterable. The except block at line 393 only catches ValueError, so the TypeError propagates and kills the thread.

Impact

After a single transient API failure:

  1. The daemon refresh thread dies silently (no log, no restart)
  2. _state is never updated again
  3. The bot continues operating with a stale orderbook indefinitely
  4. Stale prices/positions lead to incorrect order placement

This is particularly easy to trigger with the rate limiting described in #78.

Reproduction

  1. Start the market maker
  2. Temporarily block or rate-limit the CLOB API (e.g. firewall rule, or wait for a 429)
  3. _run_get_orders() returns None
  4. Debug log crashes the thread
  5. No further orderbook refreshes happen

Fix

Either guard the log:

if orders is not None:
    self.logger.debug(
        f"Fetched the order book"
        f" (orders: {[order.id for order in orders]}, "
        ...
    )

Or broaden the exception handler from except ValueError to except Exception so transient failures don't kill the thread.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions