{"record":{"id":"a6991decf159795d","repo":"ramensoftware/windhawk","slug":"invalid-request","errorCode":"INVALID_REQUEST","errorMessage":"Not a valid update suppression: \"${suppression}\"","messagePattern":"Not a valid update suppression: \"(.+?)\"","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/windhawk-frontend/apps/windhawk-frontend/src/app/webviewIPC.ts","lineNumber":1024,"sourceCode":"  >('getModConfig', selector);\n  return {\n    getModConfig: result.postMessage,\n    getModConfigPending: result.pending,\n  };\n}\n\nexport function useUpdateModConfig() {\n  const selector = useCallback(\n    (mockData: MockDataRegistry, request: UpdateModConfigData) => {\n      // The host refuses a suppression outside the grammar, so the mock refuses\n      // it too: a write no host would take must not read here as one that was.\n      const suppression = request.config.updatesDisabledForVersion;\n      if (suppression !== undefined && !isValidSuppression(suppression)) {\n        return {\n          modId: request.modId,\n          succeeded: false,\n          error: {\n            code: 'INVALID_REQUEST',\n            message: `Not a valid update suppression: \"${suppression}\"`,\n          },\n        };\n      }\n      return {\n        modId: request.modId,\n        succeeded: true,\n      };\n    },\n    []\n  );\n  const result = usePostMessageWithReplyWithMock<\n    UpdateModConfigData,\n    UpdateModConfigReplyData\n  >('updateModConfig', selector);\n  return {\n    updateModConfig: result.postMessage,\n    updateModConfigPending: result.pending,","sourceCodeStart":1006,"sourceCodeEnd":1042,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk-frontend/apps/windhawk-frontend/src/app/webviewIPC.ts#L1006-L1042","documentation":"The webview IPC handler for setting update suppression validates the requested suppression string with isValidSuppression before applying it. An unrecognized value (e.g. a malformed version string) is rejected with code INVALID_REQUEST instead of being passed to the backend.","triggerScenarios":"Sending a webview IPC request with config.updatesDisabledForVersion set to a value that fails isValidSuppression (undefined is allowed and means 'no suppression').","commonSituations":"Frontend code building the suppression string from user input or a loosely-typed version field; version format changes between components; stale/incorrect values persisted in settings.","solutions":["Print the offending value and compare it against what isValidSuppression accepts (likely a valid version string format).","Fix the producer of updatesDisabledForVersion to send the expected version format.","Guard in the caller: only set updatesDisabledForVersion when a valid version is available, otherwise omit the field."],"exampleFix":"// before\nconst config = { updatesDisabledForVersion: version.trim().toLowerCase() };\n// after\nconst config = semver.valid(version) ? { updatesDisabledForVersion: semver.clean(version) } : {};","handlingStrategy":"validation","validationCode":"const suppression = config.updatesDisabledForVersion;\nif (suppression !== undefined && !isValidSuppression(suppression)) {\n  throw new Error(`Refusing to send invalid suppression: ${suppression}`);\n}","typeGuard":"const isValidSuppression = (s: unknown): s is string =>\n  typeof s === 'string' && /^\\d+\\.\\d+(\\.\\d+)?$/.test(s);","tryCatchPattern":"try {\n  await setUpdateSuppression(config);\n} catch (e) {\n  if (e.code === 'INVALID_REQUEST') {\n    console.error('Suppression rejected:', e.message);\n    resetSuppressionSetting();\n  } else throw e;\n}","preventionTips":["Sanitize version strings with semver.clean() before assigning updatesDisabledForVersion.","Omit the field entirely (undefined) when there is no valid suppression instead of sending empty/garbage values.","Add a unit test for isValidSuppression covering the version formats you emit."],"tags":["ipc","validation","version"],"backgroundTag":"invalid-config-value","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"}