{"record":{"id":"f5cad50a0786998c","repo":"ramensoftware/windhawk","slug":"missing-path-value","errorCode":null,"errorMessage":"Missing path value","messagePattern":"Missing path value","errorType":"exception","errorClass":"std::runtime_error","httpStatus":null,"severity":"error","filePath":"src/windhawk/engine/storage_manager.cpp","lineNumber":24,"sourceCode":"\nextern HINSTANCE g_hDllInst;\n\nnamespace {\n\n// REG_NOTIFY_THREAD_AGNOSTIC keeps the notification alive after the thread that\n// registered it exits, and lets it be re-armed from another thread. The main\n// loop relies on this: it hops between threads.\nconstexpr DWORD kRegNotifyChangeKeyValueFlags = REG_NOTIFY_CHANGE_NAME |\n                                                REG_NOTIFY_CHANGE_LAST_SET |\n                                                REG_NOTIFY_THREAD_AGNOSTIC;\n\nstd::filesystem::path PathFromStorage(\n    const PortableSettings& storage,\n    PCWSTR valueName,\n    const std::filesystem::path& baseFolderPath) {\n    auto storedPath = storage.GetString(valueName).value_or(L\"\");\n    if (storedPath.empty()) {\n        throw std::runtime_error(\"Missing path value\");\n    }\n\n#ifndef _WIN64\n    BOOL isWow64;\n    if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) {\n        // Get the native Program Files path regardless of the current process\n        // architecture.\n        storedPath =\n            Functions::ReplaceAll(storedPath, L\"%ProgramFiles%\",\n                                  L\"%ProgramW6432%\", /*ignoreCase=*/true);\n    }\n#endif  // _WIN64\n\n    auto expandedPath =\n        wil::ExpandEnvironmentStrings<std::wstring>(storedPath.c_str());\n\n    // Some processes, e.g. csrss.exe, have a limited amount of environment\n    // variables set. Specifically, we need %ProgramData%, so if it's missing,","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk/engine/storage_manager.cpp#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Restore or recreate the Windhawk settings file so the expected path keys are present (reinstalling/repairing Windhawk regenerates defaults).","Re-add the missing path setting to your portable settings/config file.","If the file was hand-edited, revert to a backup that includes the path entries.","Check for a failed upgrade/migration that dropped settings and rerun setup."],"exampleFix":"// before (portable settings file)\n[Storage]\n; ModsPath missing\n// after\n[Storage]\nModsPath=D:\\Windhawk\\Mods","handlingStrategy":"try-catch","validationCode":"// before constructing StorageManager, confirm required keys exist\nfor (PCWSTR key : {L\"ModsPath\", L\"CompiledModsPath\" /* etc */}) {\n    if (settings.GetString(key).value_or(L\"\").empty()) {\n        LOG(L\"Storage setting '%s' is missing\", key);\n        RestoreDefaultSettings();\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    StorageManager::GetInstance();\n} catch (const std::runtime_error& e) {\n    if (std::string_view(e.what()) == \"Missing path value\") {\n        LOG(L\"Storage settings incomplete; regenerating defaults\");\n        ResetStorageSettingsToDefaults();\n    }\n}","preventionTips":["Back up the Windhawk settings file before manual edits or upgrades.","After updates, verify all storage path keys are present in the settings store.","Keep portable settings files complete when copying between machines.","Catch this during first-run setup and write defaults instead of crashing."],"tags":["windhawk","storage","config","paths"],"backgroundTag":"missing-required-config-field","analyzedSha":"61d99ed8e182e1af1b60109612b6763ad1b4b74e","analyzedAt":"2026-09-12T14:02:41.115Z","contentChangedAt":"2026-09-12T14:02:41.115Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}