mihomo-party-org/clash-party · error · Error

useControledMihomoConfig must be used within a ControledMiho

Error message

useControledMihomoConfig must be used within a ControledMihomoConfigProvider

What it means

useControledMihomoConfig reads ControledMihomoConfigContext and throws 'useControledMihomoConfig must be used within a ControledMihomoConfigProvider' when the context is undefined. This two-way binding config (mihomo runtime settings synced with backend) must be consumed beneath its provider; consuming elsewhere is treated as a programming error.

Source

Thrown at src/renderer/src/hooks/use-controled-mihomo-config.tsx:56

    window.electron.ipcRenderer.on('controledMihomoConfigUpdated', handler)
    return (): void => {
      window.electron.ipcRenderer.removeListener('controledMihomoConfigUpdated', handler)
    }
  }, [mutateControledMihomoConfig])

  return (
    <ControledMihomoConfigContext.Provider
      value={{ controledMihomoConfig, mutateControledMihomoConfig, patchControledMihomoConfig }}
    >
      {children}
    </ControledMihomoConfigContext.Provider>
  )
}

export const useControledMihomoConfig = (): ControledMihomoConfigContextType => {
  const context = useContext(ControledMihomoConfigContext)
  if (context === undefined) {
    throw new Error('useControledMihomoConfig must be used within a ControledMihomoConfigProvider')
  }
  return context
}

View on GitHub (pinned to 911e090537)

Solutions

  1. Hoist <ControledMihomoConfigProvider> to the root/layout that wraps every consumer of the hook.
  2. Verify provider and hook resolve to a single module instance in the bundle.
  3. Wrap conditionally rendered consumers (modals, portals) inside the provider subtree or pass config down via props.
  4. For tests, add the provider to the render wrapper.

Example fix

// before
function Widget() {
  const { controledMihomoConfig } = useControledMihomoConfig()
// after
;<ControledMihomoConfigProvider>
  <Widget />
</ControledMihomoConfigProvider>
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure provider wraps consuming routes
;<ControledMihomoConfigProvider>
  <Routes />
</ControledMihomoConfigProvider>

Try / catch

let mihomoConfig
try {
  mihomoConfig = useControledMihomoConfig()
} catch {
  mihomoConfig = { controledMihomoConfig: {}, setControledMihomoConfig: () => {} }
}

Prevention

When it happens

Trigger: A component calls useControledMihomoConfig() while rendered outside <ControledMihomoConfigProvider>; the provider is conditionally mounted (e.g. only on the settings page) while other routes consume the hook; tests or modals render the consumer without the provider.

Common situations: New UI (e.g. a proxy settings widget) added on a page that lacks the provider; provider placed after a Suspense boundary that delays it; duplicate module resolution splitting the context instance between provider and hook.

Related errors


AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30). Data as JSON: /api/errors/c2b31f1ea7253331. Report an issue: GitHub.