{"record":{"id":"0f3ef680901678f8","repo":"BloopAI/vibe-kanban","slug":"machine-client-is-required-0f3ef6","errorCode":null,"errorMessage":"Machine client is required","messagePattern":"Machine client is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/dialogs/settings/settings/SettingsMachineUserSystemProvider.tsx","lineNumber":25,"sourceCode":"  children,\n}: {\n  children: ReactNode;\n}) {\n  const machineClient = useSettingsMachineClient();\n  const queryKey = useMemo(() => {\n    if (machineClient?.target.kind === 'local') {\n      return ['user-system', 'local'] as const;\n    }\n\n    return [\n      'user-system',\n      'settings-machine',\n      machineClient?.target.id ?? 'unselected',\n    ] as const;\n  }, [machineClient]);\n  const loadConfig = useCallback(() => {\n    if (!machineClient) {\n      throw new Error('Machine client is required');\n    }\n\n    return machineClient.getConfig();\n  }, [machineClient]);\n  const saveConfig = useCallback(\n    (\n      config: Parameters<NonNullable<typeof machineClient>['saveConfig']>[0]\n    ) => {\n      if (!machineClient) {\n        throw new Error('Machine client is required');\n      }\n\n      return machineClient.saveConfig(config);\n    },\n    [machineClient]\n  );\n\n  const { value } = useUserSystemController({","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/dialogs/settings/settings/SettingsMachineUserSystemProvider.tsx#L7-L43","documentation":"SettingsMachineUserSystemProvider builds config load/save callbacks around an optional `machineClient` prop. `loadConfig` is a stable callback that must return `machineClient.getConfig()`, so when the client is absent (null/undefined) it throws 'Machine client is required' rather than returning a rejected promise. This is an intentional programming-error guard: the settings dialog should never be mounted without a machine client.","triggerScenarios":"Rendering SettingsMachineUserSystemProvider without a machineClient prop (or with undefined while machine data is still loading) and then invoking the config-loading path, e.g. via useMachineUserSystem/useConfig hooks that call loadConfig().","commonSituations":"Opening the machine settings dialog before the machine client hook has resolved; a parent conditionally rendering the provider too early; a refactor renaming/removing the machineClient prop while defaults swallow it.","solutions":["Do not render SettingsMachineUserSystemProvider until machineClient is defined (guard in the parent: `{machineClient && <SettingsMachineUserSystemProvider machineClient={machineClient}/>}`).","In a hook consumer, check `machineClient` before calling loadConfig/saveConfig and skip/return early.","If the client loads asynchronously, show a loading state while it is undefined instead of mounting the provider."],"exampleFix":"// before\n<SettingsMachineUserSystemProvider machineClient={machineClient} />\n// after\n{machineClient ? (\n  <SettingsMachineUserSystemProvider machineClient={machineClient} />\n) : (\n  <Spinner />\n)}","handlingStrategy":"try-catch","validationCode":"if (!machineClient) {\n  // render loading state or skip mounting the provider\n  return <Spinner />;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const config = loadConfig();\n} catch (err) {\n  if (err instanceof Error && err.message === 'Machine client is required') {\n    // machineClient not ready — wait or re-render when it resolves\n  }\n}","preventionTips":["Conditionally mount SettingsMachineUserSystemProvider only after machineClient resolves","Disable config UI actions while machineClient is undefined","Type the prop as required and let TypeScript force callers to narrow it first"],"tags":["react","null-check","provider","settings"],"backgroundTag":"required-dependency-missing","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}