How Holehe Handles Errors During Module Execution: Architecture & Code Analysis

Holehe isolates every service check inside asynchronous modules and wraps them in a global try-except handler that catches any exception, records a standardized error object, and continues execution without aborting the entire email reconnaissance scan.

Holehe is an open-source OSINT tool that checks for account existence across hundreds of services. Understanding how Holehe error handling works during module execution is essential for contributors and security researchers who require reliable reconnaissance even when individual APIs fail or network issues occur. The codebase implements a resilient two-layered defense strategy that combines centralized exception catching with localized error management inside individual service modules.

Global Exception Handling in the Core Driver

The main execution driver in holehe/core.py provides a safety net through the launch_module coroutine. This function acts as a universal wrapper that executes every module inside a broad try-except block, ensuring that no unhandled exception can crash the entire scanning process.

Located at lines 66-78 in holehe/core.py, the launch_module function implements the following pattern:

async def launch_module(module, email, client, out):
    try:
        await module(email, client, out)          # ← module’s normal execution path

    except Exception:                           # ← catches any uncaught exception

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

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

When a module raises an exception—whether due to network timeouts, unexpected HTTP responses, or coding bugs—the except block intercepts it, extracts the module name from its string representation, and appends a uniform error dictionary to the shared out collector. This graceful degradation allows Holehe to complete full scans even when multiple services are misbehaving.

Local Error Handling in Individual Modules

Beyond the global safety net, individual modules implement targeted error handling for anticipated failure points. This localized approach allows modules to distinguish between different error types, particularly rate limiting versus technical failures.

The Blablacar module (holehe/modules/transport/blablacar.py, lines 26-38) demonstrates this pattern when fetching authentication tokens:

try:
    appToken = await client.get("https://www.blablacar.fr/register", headers=headers)
    appToken = appToken.text.split('"appToken":"')[1].split('"')[0]
except Exception:
    out.append({
        "name": name, "domain": domain,
        "rateLimit": True, "exists": False,
        "emailrecovery": None, "phoneNumber": None, "others": None
    })
    return None

In this example, the module specifically catches token acquisition failures and marks them as rateLimit: True rather than generic errors. This distinction allows users to differentiate between temporary blocks and permanent service outages. Similar patterns appear across the codebase in modules like instagram.py and paypal.py, where localized try-except blocks wrap API requests and translate specific HTTP failures into standardized result objects.

Standardized Error Response Schema

Whether caught locally or by the global handler, all errors in Holehe conform to a consistent dictionary schema. This standardization enables the rendering engine to process results uniformly without parsing heterogeneous exception types.

The error object structure always includes these fields:

  • name: The service identifier extracted from the module function
  • domain: The target website domain
  • rateLimit: Boolean indicating if the error represents rate limiting
  • error: Boolean indicating a general execution failure
  • exists: Boolean indicating account existence (always False for errors)
  • emailrecovery: Account recovery email (null for errors)
  • phoneNumber: Associated phone number (null for errors)
  • others: Additional metadata (null for errors)

A typical error entry appears as:

{
  "name": "blablacar",
  "domain": "blablacar.com",
  "rateLimit": false,
  "error": true,
  "exists": false,
  "emailrecovery": null,
  "phoneNumber": null,
  "others": null
}

This schema ensures that the results collector (out) maintains type consistency regardless of which module fails or how the failure occurs.

Rendering Errors in the Output

During result presentation, Holehe visually distinguishes errors from successful lookups. The print_result function in holehe/core.py (approximately lines 26-32) checks for the error flag and renders it in red with a distinctive warning marker:

elif "error" in results.keys() and results["error"] and args.onlyused == False:
    websiteprint = print_color("[!] " + results["domain"] + toprint, "red", args)
    print(websiteprint)

This visual feedback immediately alerts users that a specific service check encountered an issue, while the scan continues processing remaining modules. The combination of structured data storage and clear visual indicators makes Holehe error handling both machine-parseable and human-readable.

Summary

  • Global Protection: The launch_module coroutine in holehe/core.py wraps every module in a broad try-except block that catches any exception, preventing individual service failures from crashing the entire scan.
  • Local Intelligence: Individual modules implement specific try-except blocks to handle anticipated errors like rate limiting or token acquisition failures, allowing nuanced error categorization.
  • Schema Consistency: All errors return a standardized dictionary with error and rateLimit boolean flags, ensuring the results collector maintains uniform structure regardless of failure type.
  • Visual Feedback: The rendering engine displays errors in red with a [!] prefix, providing immediate visual indication of service check failures while allowing the scan to complete.

Frequently Asked Questions

What happens when a Holehe module crashes during execution?

When a module raises an uncaught exception, the global launch_module function in holehe/core.py intercepts it at line 66-78, appends an error object with "error": True to the results list, and continues executing remaining modules. The scan completes normally, with the failed service marked in red output.

How does Holehe distinguish between rate limiting and technical errors?

Modules use localized try-except blocks to catch specific failure modes. When rate limiting is detected (usually through HTTP status codes or response parsing), modules set rateLimit: True in the output dictionary. Technical failures caught by the global handler in launch_module set error: True instead, allowing users to differentiate between temporary blocks and execution failures.

What is the exact structure of Holehe's error response?

Every error response follows a consistent schema containing eight fields: name (service identifier), domain (target site), rateLimit (boolean), error (boolean), exists (boolean, always false for errors), emailrecovery (null), phoneNumber (null), and others (null). This structure ensures downstream tools can reliably parse error states.

Where is the global error handler located in the Holehe codebase?

The global error handler resides in holehe/core.py within the launch_module async function (lines 66-78). This centralized wrapper executes every module through a single try-except block, making it the primary defense against unhandled exceptions during module execution.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →