ramensoftware/windhawk · error · std::runtime_error

Failed to initialize MinHook

Error message

Failed to initialize MinHook

What it means

Windhawk's customization session initializes the MinHook hooking engine by calling MH_Initialize() during session construction. If MinHook reports any status other than MH_OK (e.g. it was already initialized or an internal buffer allocation failed), the scope constructor logs the status code and throws std::runtime_error to abort the session. A failed hooking-engine init means no hooks can be installed for the customization.

Solutions

  1. Check whether another customization session or module already called MH_Initialize and is still active; ensure sessions are torn down (MH_Uninitialize) before a new one starts.
  2. Read the logged MH_STATUS code: MH_ERROR_ALREADY_INITIALIZED means MinHook is usable as-is and the throw may be overly strict for your flow.
  3. Retry session creation once the conflicting session has exited.
  4. Report to Windhawk if it reproduces consistently with a single session, including the status code from the log.

Example fix

// before
MH_STATUS status = MH_Initialize();
if (status != MH_OK) {
    LOG(L"MH_Initialize failed with %d", status);
    throw std::runtime_error("Failed to initialize MinHook");
}
// after
MH_STATUS status = MH_Initialize();
if (status == MH_ERROR_ALREADY_INITIALIZED) {
    LOG(L"MinHook already initialized; reusing");
} else if (status != MH_OK) {
    LOG(L"MH_Initialize failed with %d", status);
    throw std::runtime_error("Failed to initialize MinHook");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// best-effort pre-check: MinHook is already usable if MH_Initialize would return ALREADY_INITIALIZED
// no public pre-check exists; catch and inspect the logged MH_STATUS instead

Try / catch

try {
    auto session = CreateCustomizationSession(...);
} catch (const std::runtime_error& e) {
    if (std::string_view(e.what()) == "Failed to initialize MinHook") {
        LOG(L"MinHook init failed; retrying after cleanup");
        // tear down conflicting sessions, then retry once
    }
}

Prevention

When it happens

Trigger: Creating a CustomizationSession with WH_HOOKING_ENGINE_MINHOOK enabled when MinHook is already initialized (MH_ERROR_ALREADY_INITIALIZED), or when MH_Initialize fails to allocate its internal structures.

Common situations: Two overlapping customization sessions trying to initialize MinHook in the same process; a previously crashed/partially cleaned-up session leaving MinHook initialized; low-memory conditions.

Related errors


AI-assisted analysis of ramensoftware/windhawk@61d99ed8e1 (2026-09-12). Data as JSON: /api/errors/ae5ac7591a6a891e. Report an issue: GitHub.

Appendix: source

Thrown at src/windhawk/engine/customization_session.cpp:218

        LOG(L"AfterInit failed: %S", e.what());
    }
}

CustomizationSession::~CustomizationSession() {
    try {
        m_modsManager.BeforeUninit();
    } catch (const std::exception& e) {
        LOG(L"BeforeUninit failed: %S", e.what());
    }
}

#ifdef WH_HOOKING_ENGINE_MINHOOK
CustomizationSession::MinHookScopeInit::MinHookScopeInit(
    MH_THREAD_FREEZE_METHOD freezeMethod) {
    MH_STATUS status = MH_Initialize();
    if (status != MH_OK) {
        LOG(L"MH_Initialize failed with %d", status);
        throw std::runtime_error("Failed to initialize MinHook");
    }

    MH_SetThreadFreezeMethod(freezeMethod);

#ifdef WH_HOOKING_ENGINE_MINHOOK_DETOURS
    MH_SetBulkOperationMode(
        /*continueOnError=*/TRUE, [](LPVOID pTarget, NTSTATUS detoursStatus) {
            LOG(L"Hooking operation failed for %p with status 0x%08X", pTarget,
                detoursStatus);
        });
#endif
}

CustomizationSession::MinHookScopeInit::~MinHookScopeInit() {
    MH_STATUS status = MH_Uninitialize();
    if (status != MH_OK) {
        LOG(L"MH_Uninitialize failed with status %d", status);
    }

View on GitHub (pinned to 61d99ed8e1)