# How Holehe Handles Rate Limiting: Exception-Based Detection in the Core Engine

> Discover how Holehe handles rate limiting using exception-based detection in its core engine. It flags services automatically avoiding scan crashes.

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

---

**Holehe treats any exception during a module's HTTP request as a rate-limit condition, automatically flagging the service with `rateLimit: True` instead of crashing the entire scan.**

Holehe is an open-source email investigation tool that checks registration status across hundreds of websites. Understanding how it handles rate limiting is essential for interpreting results and avoiding false negatives when services temporarily block requests. This article examines the detection mechanism implemented in `megadose/holehe`.

## The Core Detection Mechanism: Generic Exception Wrapping

Rate-limit detection in Holehe is centralized in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) through the `launch_module` function. Rather than implementing per-service rate-limit logic, Holehe uses a broad exception handler that assumes any failure indicates throttling.

### The launch_module Wrapper (Lines 66-78)

```python

# holehe/core.py – launch_module

async def launch_module(module, email, client, out):
    try:
        await module(email, client, out)
    except Exception:                              # any error → assumed rate-limit

        name = str(module).split('<function ')[1].split(' ')[0]
        out.append({
            "name": name,
            "domain": data[name],
            "rateLimit": True,                      # flag set here

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

```

The `launch_module` function receives four parameters:
- `module` — the service-specific checking function
- `email` — the target email address
- `client` — a shared `httpx.AsyncClient` instance
- `out` — a list that accumulates results

When **any exception** is raised—from HTTP 429 responses to connection timeouts to DNS errors—the wrapper catches it generically and populates a standardized result dictionary with `"rateLimit": True`.

## Visual Indicators in CLI Output

After all modules complete, `print_result` renders the rate-limit status in the terminal table. Services flagged as rate-limited appear with a yellow `[x]` marker.

### The print_result Filter (Lines 22-26)

```python

# holehe/core.py – print_result

if results["rateLimit"] and args.onlyused == False:
    websiteprint = print_color("[x] " + results["domain"], "yellow", args)
    print(websiteprint)

```

The `[x]` symbol distinguishes rate-limited services from:
- `[+]` — email found/registered (green)
- `[-]` — email not found (red)

This visual encoding lets users immediately spot which services couldn't be verified due to throttling.

## The frequent_rate_limit Hint Flag

Some modules declare a class-level or module-level variable `frequent_rate_limit = True` to indicate services known for aggressive throttling. This metadata appears only in raw JSON output and does not alter detection behavior.

### Example: Wattpad Module

```python

# holehe/modules/social_media/wattpad.py (lines 9-14)

frequent_rate_limit = True

async def wattpad(email, client, out):
    # ... request logic ...

    out.append({..., "rateLimit": True, ...})

```

Similar declarations exist in [`holehe/modules/transport/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transport/blablacar.py) and other modules. These flags serve as documentation for users reviewing verbose output, not as runtime logic.

## Practical Examples

### CLI Usage Showing Rate Limits

```bash
$ holehe you@example.com
[+] Email used
[x] twitter.com          ← rate-limit detected (yellow [x])
[-] facebook.com
[+] github.com
...

```

The `[x] twitter.com` entry indicates the Twitter check failed—likely due to HTTP 429 or connection timeout—and Holehe recorded it as rate-limited rather than unregistered.

### Programmatic Inspection

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

async def demo(email):
    async with httpx.AsyncClient() as client:
        out = []
        from holehe.modules.social_media import twitter
        await launch_module(twitter.twitter, email, client, out)
        print(out)
        # [{'name': 'twitter', 'domain': 'twitter.com', 

        #   'rateLimit': True, 'error': True, 'exists': False, ...}]

asyncio.run(demo('you@example.com'))

```

The `out` list contains the rate-limit flag, allowing automated pipelines to distinguish between "email not found" and "check inconclusive due to throttling."

## Key Source Files

| File | Purpose |
|------|---------|
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | Implements `launch_module` exception wrapper and `print_result` rendering; contains the primary rate-limit detection logic |
| [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) | Typical module showing request patterns that may trigger rate-limit flags |
| [`holehe/modules/social_media/wattpad.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/wattpad.py) | Module with `frequent_rate_limit = True` hint flag for known-throttled services |
| [`holehe/modules/transport/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transport/blablacar.py) | Additional example of the frequency hint flag |

## Summary

- **Holehe handles rate limiting through a generic exception wrapper** in `launch_module` that flags any failed request as `"rateLimit": True`
- **No per-service rate-limit logic exists**—HTTP 429s, timeouts, and DNS failures are treated identically
- **CLI output uses yellow `[x]` markers** to visually indicate throttled services
- **`frequent_rate_limit` hints** document known-problematic services but don't affect detection
- **The shared `httpx.AsyncClient`** enables efficient concurrent requests while the central wrapper ensures graceful degradation

## Frequently Asked Questions

### What HTTP status codes trigger Holehe's rate-limit detection?

Holehe does not inspect status codes directly. Any exception raised during module execution—including but not limited to HTTP 429, connection timeouts, SSL errors, or DNS failures—triggers the generic exception handler in `launch_module` and sets `"rateLimit": True`. This design prioritizes robustness over precision.

### Can I disable rate-limit detection or treat rate-limited services as "not found"?

No configuration option changes the rate-limit detection behavior. The `launch_module` function in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) hardcodes the exception-to-rate-limit mapping. Users filtering results must post-process the output and interpret `"rateLimit": True` according to their needs.

### Why do some modules set `frequent_rate_limit = True`?

This flag serves as documentation for services like Wattpad and Blablacar that are known to throttle aggressively. It appears only in verbose/JSON output and has no effect on the detection mechanism. The actual rate-limit flag still depends on whether the request raises an exception.