{"record":{"id":"8749e7e6c1139443","repo":"ramensoftware/windhawk","slug":"missing-path-value-valuename","errorCode":null,"errorMessage":"Missing path value: {valueName}","messagePattern":"Missing path value: (.+?)","errorType":"exception","errorClass":"std::runtime_error","httpStatus":null,"severity":"error","filePath":"src/windhawk/app/storage_manager.cpp","lineNumber":23,"sourceCode":"\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.\nconstexpr DWORD kRegNotifyChangeKeyValueFlags =\n    REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_THREAD_AGNOSTIC;\n\nstd::filesystem::path PathFromStorage(\n    const PortableSettings& storage,\n    PCWSTR valueName,\n    const std::filesystem::path& baseFolderPath,\n    bool optional = false) {\n    auto storedPath = storage.GetString(valueName).value_or(L\"\");\n    if (storedPath.empty()) {\n        if (optional) {\n            return {};\n        }\n        throw std::runtime_error(\"Missing path value: \" + CStringA(valueName));\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\n        // process 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    return (baseFolderPath / expandedPath).lexically_normal();\n}\n","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk/app/storage_manager.cpp#L5-L41","documentation":"PathFromStorage reads a path-like string value from the settings storage and, unless the value is marked optional, throws when the stored value is empty or missing. It guards the constructor paths of StorageManager which must know where settings/engine data live before any operation can proceed.","triggerScenarios":"StorageManager::StorageManager or StorageManager::GetEngineAppDataPath calling PathFromStorage with a non-optional valueName (e.g. an AppData path key) when storage.GetString(valueName) returns nothing or an empty string.","commonSituations":"Fresh install or portable-mode switch where the storage value was never written; settings storage (INI or registry) deleted or reset; hand-edited settings file with the key removed.","solutions":["Restore the missing value in the settings storage (settings.ini or the registry key)","Reinstall or run Windhawk's repair to repopulate default storage values","If the path is genuinely optional, mark the optional parameter true at the call site","Compare against a working installation to find which valueName is absent"],"exampleFix":"// before: required key missing from settings.ini\n// [Paths]  (ApplicationPath absent)\n// after\n// [Paths]\nApplicationPath=C:\\Program Files\\Windhawk","handlingStrategy":"validation","validationCode":"// confirm required values exist in storage before constructing StorageManager\nfor (auto name : requiredPathValues) {\n    if (storage.GetString(name).value_or(L\"\").empty()) throw std::runtime_error(\"setup incomplete\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    StorageManager sm(portableStorage);\n} catch (const std::exception& e) {\n    Log(L\"storage init failed: %hs\", e.what());\n}","preventionTips":["Never remove path keys from settings.ini or the registry store","Run the installer/repair after manual storage cleanup","Mark truly optional paths with optional=true at the call site"],"tags":["storage","config","cpp","windows"],"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"}