# How to Configure Event Timeouts in Bubus: A Complete Guide

> Master Bubus event timeouts with this guide. Learn to set default, instance, or handler-specific limits for reliable event management in your browser-use/bubus project.

- Repository: [Browser Use/bubus](https://github.com/browser-use/bubus)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Bubus provides a hierarchical timeout system that lets you configure default limits on the `BaseEvent` model, override them per-event instance, or set specific limits per-handler when dispatching or awaiting results.**

The `browser-use/bubus` event bus library implements a robust timeout mechanism to prevent runaway handlers from blocking your application. Whether you're building long-running background processors or latency-critical user interfaces, knowing how to configure event timeouts in Bubus ensures your system remains responsive and predictable.

## Understanding the Timeout Architecture

Bubus implements timeouts at multiple layers, from the core data model to the execution service. The system respects the most specific timeout provided, falling back to broader defaults when specific values are omitted.

### Default Event Timeout in BaseEvent

Every event in Bubus inherits from `BaseEvent` defined in [`bubus/models.py`](https://github.com/browser-use/bubus/blob/main/bubus/models.py). The model declares an `event_timeout` field with a default value of **300 seconds** (5 minutes):

```python

# bubus/models.py L22-L24

class BaseEvent(BaseModel):
    event_timeout: float | None = 300.0

```

This value serves as the global default for any event instance that does not specify its own timeout.

### Per-Handler Timeout Overrides

When the event bus executes a handler, it creates an `EventResult` object that tracks the execution. According to the source code in [`bubus/service.py`](https://github.com/browser-use/bubus/blob/main/bubus/service.py), the effective timeout for a specific handler is determined by:

```python

# bubus/service.py L972-L973 and L1099-L1100

timeout = timeout or event.event_timeout

```

This means an explicit `timeout` argument passed to the dispatch or processing method takes precedence over the event's default timeout.

## Configuring Timeouts at Different Layers

You can configure timeouts globally, per-instance, per-handler, or when awaiting results. Each approach targets different use cases within the Bubus framework.

### Set a Global Default Timeout

To change the default for all events of a specific type, subclass `BaseEvent` and override the `event_timeout` field:

```python
from bubus.models import BaseEvent

class MyEvent(BaseEvent):
    event_timeout: float | None = 60.0  # 1 minute default for all MyEvent instances

```

This approach ensures consistency across your application for specific event types without manually passing timeouts during instantiation.

### Configure Per-Instance Timeouts

For one-off events requiring different limits, pass the `event_timeout` parameter during construction:

```python
from bubus.models import BaseEvent

# Create an event with a 5-second timeout

event = BaseEvent(
    event_type='QuickTask',
    event_timeout=5.0
)
bus.dispatch(event)

```

This overrides the class default for that specific instance only.

### Override Timeouts Per-Handler

When dispatching events through low-level APIs like `step` or `process_event`, you can specify a handler timeout that overrides both the event default and instance values:

```python

# Force a 2-second limit regardless of event.event_timeout

await bus.step(event, timeout=2.0)

```

This is useful when the same event type might be processed by different handlers with varying latency requirements.

### Timeouts When Waiting for Events

The `expect` and `wait_until_idle` methods accept timeout parameters to prevent indefinite blocking:

```python

# bubus/service.py L591-L617 (expect) and L817-L839 (wait_until_idle)

# Wait up to 3 seconds for a specific event type

user_evt = await bus.expect('UserActionEvent', timeout=3.0)

# Wait until bus is idle, but timeout after 10 seconds

await bus.wait_until_idle(timeout=10.0)

```

If the timeout expires, these methods raise `asyncio.TimeoutError`.

### Timeouts When Awaiting Results

When retrieving results from specific handlers, pass the timeout to `event_result`:

```python

# bubus/models.py L485-L486

result = await my_event.event_result(
    handler_name='process_data',
    timeout=4.5
)

```

This forwards the timeout directly to `asyncio.wait_for` internally.

## What Happens When a Timeout Occurs

Understanding the timeout behavior helps you implement proper error handling and cleanup logic.

When a handler exceeds its allotted time, Bubus performs the following actions as implemented in [`bubus/service.py`](https://github.com/browser-use/bubus/blob/main/bubus/service.py) (lines 1184-1194):

1. **Task Cancellation**: The handler's asyncio task is cancelled immediately.
2. **Error Recording**: A `TimeoutError` is recorded on the associated `EventResult` object.
3. **Child Event Cleanup**: Any child events spawned by the timed-out handler are cancelled via `event.event_cancel_pending_child_processing`.
4. **Structured Logging**: The system logs a timeout tree via `log_timeout_tree` to help diagnose which handler exceeded its budget.

This comprehensive cleanup ensures that timeout cascades don't leave orphaned tasks or inconsistent state in your application.

## Summary

- **Bubus provides a hierarchical timeout system** with defaults at the `BaseEvent` level (300 seconds), overridable per-instance, per-handler, and during wait operations.
- **Configure global defaults** by subclassing `BaseEvent` and setting `event_timeout`.
- **Override per-instance** by passing `event_timeout` during event construction.
- **Override per-handler** by passing `timeout` to `bus.step()` or similar low-level APIs.
- **Set wait timeouts** using the `timeout` parameter in `bus.expect()` and `bus.wait_until_idle()`.
- **Await results with timeouts** by passing `timeout` to `event.event_result()`.
- **Timeout behavior includes** task cancellation, error recording, child event cleanup, and structured logging via `log_timeout_tree` in [`bubus/service.py`](https://github.com/browser-use/bubus/blob/main/bubus/service.py).

## Frequently Asked Questions

### What is the default timeout for events in Bubus?

The default timeout is **300 seconds** (5 minutes), defined in the `event_timeout` field of the `BaseEvent` model in [`bubus/models.py`](https://github.com/browser-use/bubus/blob/main/bubus/models.py) (lines 22-24). You can override this default globally by subclassing `BaseEvent` or per-instance when creating specific events.

### How do I set a different timeout for a specific event handler?

You can override the timeout for a specific handler dispatch by passing the `timeout` argument to low-level methods like `bus.step()`. According to the implementation in [`bubus/service.py`](https://github.com/browser-use/bubus/blob/main/bubus/service.py) (lines 972-973 and 1099-1100), the explicit `timeout` parameter takes precedence over the event's `event_timeout` attribute.

### What exception is raised when an event times out in Bubus?

When waiting for events using `bus.expect()` or `bus.wait_until_idle()`, Bubus raises `asyncio.TimeoutError` if the specified timeout expires. For handler execution timeouts, the system records a `TimeoutError` on the `EventResult` object and cancels the handler task, as implemented in [`bubus/service.py`](https://github.com/browser-use/bubus/blob/main/bubus/service.py) (lines 1184-1194).

### Does Bubus clean up child events when a parent handler times out?

Yes. When a handler exceeds its timeout budget, Bubus automatically cancels any child events that were spawned during the handler's execution. This cleanup is performed via `event.event_cancel_pending_child_processing` as part of the timeout handling logic in [`bubus/service.py`](https://github.com/browser-use/bubus/blob/main/bubus/service.py), ensuring that timeout cascades don't leave orphaned tasks running.