{"record":{"id":"68aeee5e0a9de5e3","repo":"mihomo-party-org/clash-party","slug":"useappconfig-must-be-used-within-an-appconfigprovi","errorCode":null,"errorMessage":"useAppConfig must be used within an AppConfigProvider","messagePattern":"useAppConfig must be used within an AppConfigProvider","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/src/hooks/use-app-config.tsx","lineNumber":58,"sourceCode":"    },\n    [mutate, t]\n  )\n\n  return (\n    <AppConfigContext.Provider\n      value={{ appConfig: config, mutateAppConfig: mutate, patchAppConfig }}\n    >\n      {children}\n    </AppConfigContext.Provider>\n  )\n}\n\nconst AppConfigContext = React.createContext<AppConfigContextType | undefined>(undefined)\n\nexport const useAppConfig = (): AppConfigContextType => {\n  const context = React.useContext(AppConfigContext)\n  if (!context) {\n    throw new Error('useAppConfig must be used within an AppConfigProvider')\n  }\n  return context\n}\n","sourceCodeStart":40,"sourceCodeEnd":62,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/renderer/src/hooks/use-app-config.tsx#L40-L62","documentation":"useAppConfig reads AppConfigContext, created with React.createContext(undefined). If no <AppConfigProvider> (or equivalent Provider supplying AppConfigContextType) is present above the caller, the context is undefined and the hook throws 'useAppConfig must be used within an AppConfigProvider'. It enforces that app configuration is only read through a properly mounted provider.","triggerScenarios":"Calling useAppConfig() in a component rendered outside the AppConfig provider tree (root layout missing the provider, a portal/modal escaping the tree, or a plain TS module invoking the hook); duplicate module instances splitting provider and consumer contexts.","commonSituations":"Adding a new settings page and forgetting to add the provider at the app root; Storybook/tests rendering the component bare; refactors that moved the provider below a route that still consumes the hook.","solutions":["Mount <AppConfigProvider> at the top of the app (root entry) so all consumers are descendants.","Ensure the hook and provider are imported from the same module (no duplicate bundle copies).","In tests/Storybook, wrap the component in the provider or a decorator.","If a sane default exists, give createContext a default value instead of undefined."],"exampleFix":"// before\ncreateRoot(document.getElementById('root')!).render(<App />)\n// after\ncreateRoot(document.getElementById('root')!).render(\n  <AppConfigProvider>\n    <App />\n  </AppConfigProvider>\n)","handlingStrategy":"try-catch","validationCode":"// wrap the app root\ncreateRoot(rootEl).render(<AppConfigProvider><App /></AppConfigProvider>)","typeGuard":null,"tryCatchPattern":"let appConfig\ntry {\n  appConfig = useAppConfig()\n} catch {\n  appConfig = { config: defaultAppConfig, patchAppConfig: async () => {} }\n}","preventionTips":["Place AppConfigProvider at the topmost component of the renderer entry.","Keep portals/modals inside the provider subtree (render them from provider children).","Add provider wrappers in test render helpers so every test has it by default.","Avoid deep imports that could create a second copy of the hooks module."],"tags":["react","context","hook-misuse"],"backgroundTag":"hook-used-outside-provider","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}