ramensoftware/windhawk · error · std::runtime_error

Missing path value

Error message

Missing path value

What it means

PathFromStorage resolves a configured Windhawk storage path (e.g. the mods or compile artifacts folder) from PortableSettings, combining it with a base folder. If the setting value is missing or empty it throws runtime_error('Missing path value') because StorageManager cannot function without its folder locations.

Solutions

  1. Restore or recreate the Windhawk settings file so the expected path keys are present (reinstalling/repairing Windhawk regenerates defaults).
  2. Re-add the missing path setting to your portable settings/config file.
  3. If the file was hand-edited, revert to a backup that includes the path entries.
  4. Check for a failed upgrade/migration that dropped settings and rerun setup.

Example fix

// before (portable settings file)
[Storage]
; ModsPath missing
// after
[Storage]
ModsPath=D:\Windhawk\Mods
Defensive patterns

Strategy: try-catch

Validate before calling

// before constructing StorageManager, confirm required keys exist
for (PCWSTR key : {L"ModsPath", L"CompiledModsPath" /* etc */}) {
    if (settings.GetString(key).value_or(L"").empty()) {
        LOG(L"Storage setting '%s' is missing", key);
        RestoreDefaultSettings();
    }
}

Try / catch

try {
    StorageManager::GetInstance();
} catch (const std::runtime_error& e) {
    if (std::string_view(e.what()) == "Missing path value") {
        LOG(L"Storage settings incomplete; regenerating defaults");
        ResetStorageSettingsToDefaults();
    }
}

Prevention

When it happens

Trigger: StorageManager construction reading a storage key (via PathFromStorage) that has no value in the settings store — e.g. a fresh/corrupted Windhawk settings file missing the expected path entries.

Common situations: First run with an incomplete settings file; settings store wiped or partially migrated after an update; manual edits deleting a path key; portable-config files copied without the path entries.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at src/windhawk/engine/storage_manager.cpp:24

extern HINSTANCE g_hDllInst;

namespace {

// REG_NOTIFY_THREAD_AGNOSTIC keeps the notification alive after the thread that
// registered it exits, and lets it be re-armed from another thread. The main
// loop relies on this: it hops between threads.
constexpr DWORD kRegNotifyChangeKeyValueFlags = REG_NOTIFY_CHANGE_NAME |
                                                REG_NOTIFY_CHANGE_LAST_SET |
                                                REG_NOTIFY_THREAD_AGNOSTIC;

std::filesystem::path PathFromStorage(
    const PortableSettings& storage,
    PCWSTR valueName,
    const std::filesystem::path& baseFolderPath) {
    auto storedPath = storage.GetString(valueName).value_or(L"");
    if (storedPath.empty()) {
        throw std::runtime_error("Missing path value");
    }

#ifndef _WIN64
    BOOL isWow64;
    if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) {
        // Get the native Program Files path regardless of the current process
        // architecture.
        storedPath =
            Functions::ReplaceAll(storedPath, L"%ProgramFiles%",
                                  L"%ProgramW6432%", /*ignoreCase=*/true);
    }
#endif  // _WIN64

    auto expandedPath =
        wil::ExpandEnvironmentStrings<std::wstring>(storedPath.c_str());

    // Some processes, e.g. csrss.exe, have a limited amount of environment
    // variables set. Specifically, we need %ProgramData%, so if it's missing,

View on GitHub (pinned to 61d99ed8e1)