# How Holehe Manages Exceptions During Module Execution: A Deep Dive into Resilient Async Scanning

> Discover how Holehe handles exceptions during module execution. Learn how Holehe ensures uninterrupted email-lookup scans by converting failures into structured error results.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: deep-dive
- Published: 2026-08-30

---

**Holehe catches all exceptions at the core orchestration layer and inside individual modules, converting every failure into a structured error result so the email-lookup scan continues without interruption.**

Holehe is an open-source OSINT tool for checking if an email address is registered on hundreds of websites. Because it runs dozens of **async** HTTP requests concurrently using **Trio**, robust exception handling is essential. This article examines exactly how Holehe manages exceptions during module execution, from the top-level `launch_module` wrapper down to per-service error handling in individual modules.

## The Core Exception Wrapper in launch_module

At the heart of Holehe's fault tolerance is a generic `try / except` block inside `launch_module` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py). This function is responsible for invoking every module function during a scan.

```python
async def launch_module(module, email, client, out):
    try:
        await module(email, client, out)
    except Exception:                     # catches any error from the module

        name = str(module).split('<function ')[1].split(' ')[0]
        out.append({
            "name": name,
            "domain": data[name],
            "rateLimit": False,
            "error": True,                # marks the result as an error

            "exists": False,
            "emailrecovery": None,
            "phoneNumber": None,
            "others": None,
        })

```

Source: [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 66-78

This wrapper guarantees that **no single module failure crashes the entire scan**. Whether a module throws a network timeout, a parsing error, or an unexpected API response, `launch_module` catches it, extracts the module name from its string representation, and appends a standardized error entry to the shared results list.

## Module-Level Exception Handling for Service-Specific Logic

Individual modules implement their own `try / except` blocks around HTTP requests. This allows them to apply **service-specific error semantics**, particularly for distinguishing rate limits from other failures.

The Twitter module demonstrates this pattern:

```python
async def twitter(email, client, out):
    try:
        req = await client.get(
            "https://api.twitter.com/i/users/email_available.json",
            params={"email": email})
        # … normal success handling …

    except Exception:                     # any request error

        out.append({
            "name": name,
            "domain": domain,
            "method": method,
            "frequent_rate_limit": frequent_rate_limit,
            "rateLimit": True,            # signals a rate-limit / error

            "exists": False,
            "emailrecovery": None,
            "phoneNumber": None,
            "others": None,
        })

```

Source: [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) lines 11-36

Notice the key difference: the module sets `rateLimit=True` when it catches an exception, whereas the core wrapper uses `rateLimit=False`. This distinction lets downstream reporting code identify which failures are likely temporary (rate limits) versus unknown errors.

This pattern appears consistently across almost all modules in `holehe/modules/`, including Instagram, Facebook, and other social media services.

## Uniform Result Schema Enables Consistent Reporting

Both exception handling paths produce identical dictionary structures. The schema fields are:

- `name` — the service name
- `domain` — the service domain
- `rateLimit` — boolean flag for rate-limit conditions
- `error` — boolean flag for general errors
- `exists` — whether the email was found (always `False` on error)
- `emailrecovery`, `phoneNumber`, `others` — additional data fields (always `None` on error)

This uniformity allows `print_result` and other reporting functions to display errors consistently:

```bash
$ holehe user@example.com
[+] twitter.com
[!] instagram.com  # shown when the Instagram module raised an exception

```

The `[!]` prefix indicates an error or rate-limit condition, derived directly from the `error` or `rateLimit` flags in the result dictionary.

## Concurrent Execution Context: Why Exception Handling Matters

Holehe uses **Trio** to run all modules concurrently. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the main execution flow collects module tasks and runs them simultaneously:

- Without the `launch_module` wrapper, any unhandled exception in one task would propagate and potentially crash the entire nursery
- With the wrapper, each task is isolated; failures are contained and logged without affecting sibling tasks

The instrumentation in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) provides progress tracking during concurrent execution but does not participate in exception handling.

## Summary

- **Top-level safety net**: `launch_module` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) wraps every module call in `try / except`, ensuring scan continuity
- **Service-aware handling**: Individual modules catch exceptions to apply domain-specific logic like rate-limit detection
- **Structured error reporting**: Both paths populate a uniform result schema that downstream code renders consistently
- **Fault-tolerant architecture**: The combination of core and module-level handling makes Holehe resilient against transient network failures and API changes

## Frequently Asked Questions

### What happens if a Holehe module crashes completely?

The `launch_module` function in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) catches any `Exception` and records an error result. The scan continues with all other modules unaffected.

### How does Holehe distinguish between rate limits and other errors?

Modules set `rateLimit=True` when they catch request exceptions, while the core wrapper uses `rateLimit=False` for unexpected failures. The Twitter module in [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) demonstrates this service-specific handling.

### Does Holehe ever abort a scan due to a single module failure?

No. The exception handling design explicitly prevents this. Every module runs in isolation, and all failures are converted to structured results without stopping the overall execution.

### Where can I see the actual exception handling code?

The core wrapper is in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 66-78. Examples of module-level handling appear throughout `holehe/modules/`, particularly in [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) lines 11-36.