# How Holehe Handles Module Exceptions and Errors Gracefully

> Holehe gracefully handles module exceptions and errors by converting them into standardized dictionaries. Discover how holehe ensures continuous scanning and user alerts.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: internals
- Published: 2026-08-19

---

**Holehe captures all module failures in the `launch_module` coroutine within [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), converting exceptions into standardized error dictionaries that allow the scan to continue while alerting users via colored console output.**

When investigating email addresses across hundreds of platforms, a single broken site or network timeout could derail an entire OSINT operation. The `megadose/holehe` repository implements a robust fault-tolerance mechanism that isolates individual module failures, ensuring that one problematic site never aborts the complete search workflow.

## The Central Exception Handler in launch_module

The core resilience logic resides in the `launch_module` async function defined in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 66-78). This coroutine wraps every site-specific check in a broad exception trap that intercepts any runtime failure—from network timeouts to parsing errors.

```python
async def launch_module(module, email, client, out):
    try:
        await module(email, client, out)          # Normal execution

    except Exception:                            # Catch any unexpected error

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

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

```

When a module raises an exception, `launch_module` immediately constructs a standardized result dictionary with **`error: True`** and appends it to the shared `out` list. The dictionary preserves the module name and associated domain from the `data` mapping, ensuring forensic traceability even when the underlying function crashes.

## Visual Error Reporting in print_result

After collection completes, the `print_result` function (lines 26-32 in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)) renders error states to the console with distinctive red formatting. This visual feedback distinguishes failed checks from negative results or successful findings.

```python
elif "error" in results.keys() and results["error"] and args.onlyused == False:
    toprint = ""
    if results["others"] is not None and "Message" in str(results["others"].keys()):
        toprint = " Error message: " + results["others"]["errorMessage"]
    websiteprint = print_color("[!] " + results["domain"] + toprint,
                               "red", args)
    print(websiteprint)

```

The red `[!]` prefix immediately alerts investigators that a specific domain could not be checked, while optional embedded error messages provide additional diagnostic context when available.

## Why Graceful Degradation Matters for OSINT Tools

Holehe executes site checks concurrently using `trio.open_nursery()` or `asyncio` gather patterns. Without centralized exception handling in `launch_module`, a single malformed HTTP response or unexpected HTML structure would propagate upward and crash the entire orchestration layer.

By funneling every module through the same `try/except` pathway, the tool achieves **fault isolation**: successful modules return normally, failed modules return error dictionaries, and the aggregate results list always contains a deterministic entry for every queried site.

## Practical Implementation Example

The following snippet demonstrates the internal workflow, showing how exceptions automatically generate error-flagged entries without stopping execution:

```python
import asyncio, httpx
from holehe.core import import_submodules, get_functions, launch_module

async def demo(email):
    modules = import_submodules("holehe.modules")
    sites = get_functions(modules)
    client = httpx.AsyncClient(timeout=10)
    out = []

    async with trio.open_nursery() as n:
        for site in sites:
            n.start_soon(launch_module, site, email, client, out)

    await client.aclose()
    
    # Process results: error entries coexist with successful checks

    for r in out:
        if r["error"]:
            print(f"⚠️  {r['domain']} failed")
        else:
            status = "found" if r["exists"] else "not found"
            print(f"✅  {r['domain']} → {status}")

asyncio.run(demo("test@example.com"))

```

In this pattern, the `out` list contains mixed results: standard dictionaries for successful lookups and error-denoted dictionaries for failures, preserving complete audit trails.

## Summary

- **Centralized trapping**: The `launch_module` coroutine in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) wraps every module call in a `try/except` block that catches all exceptions.
- **Structured error objects**: Failed modules return dictionaries with `error: True`, `exists: False`, and domain metadata rather than crashing.
- **Visual distinction**: The `print_result` function renders errors in red with a `[!]` prefix, making failures immediately recognizable in console output.
- **Scan continuity**: Because exceptions are converted to data rather than propagated, parallel execution continues uninterrupted even when individual sites malfunction.

## Frequently Asked Questions

### How does holehe prevent one module failure from crashing the entire scan?

Holehe runs each site-specific module inside the `launch_module` coroutine, which implements a broad `except Exception` clause. When any module raises an error—whether from network timeouts, parsing failures, or unexpected HTTP responses—the exception is caught and converted into a structured error dictionary. This prevents the exception from bubbling up to the main async nursery or event loop, allowing other concurrent modules to complete normally.

### What information is included when a module reports an error?

Error entries contain the module's function name, the target domain, boolean flags indicating `rateLimit: False` and `error: True`, and null values for recovery fields. If the module populated the `others` dictionary with an error message before failing, that message is preserved and displayed in the final console output alongside the red `[!]` indicator.

### How can developers identify which specific modules failed during a scan?

Each error dictionary includes the `"name"` key derived from the module's function name and the `"domain"` key mapped from the internal `data` dictionary. When reviewing results programmatically, developers can filter the output list for entries where `result["error"] is True` to isolate problematic sites. The console output also prints the domain name in red, providing immediate visual identification of failed checks.

### Does holehe differentiate between rate limits and other types of errors?

Yes, the result schema includes a dedicated `rateLimit` boolean that operates independently from the `error` flag. While the `launch_module` exception handler sets `error: True` for any uncaught exception, modules that detect HTTP 429 responses or rate-limiting headers typically set `rateLimit: True` through their normal execution path rather than raising exceptions. This distinction allows investigators to distinguish between temporary blocking and technical failures.