{"record":{"id":"be1a9e96a7d1722c","repo":"mihomo-party-org/clash-party","slug":"missing-profile-import-handler","errorCode":null,"errorMessage":"Missing profile import handler","messagePattern":"Missing profile import handler","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/src/components/profiles/edit-info-modal.tsx","lineNumber":63,"sourceCode":"    ...item\n  })\n  const inputWidth = 'w-[400px] md:w-[400px] lg:w-[600px] xl:w-[800px]'\n  const { t } = useTranslation()\n  const isImportMode = mode === 'import'\n  const canSave =\n    !isImportMode || (values.type === 'remote' ? Boolean(values.url?.trim()) : values.file != null)\n\n  const onSave = async (): Promise<void> => {\n    try {\n      const updatedItem = {\n        ...values,\n        override: values.override?.filter(\n          (i) =>\n            overrideItems.find((t) => t.id === i) && !overrideItems.find((t) => t.id === i)?.global\n        )\n      }\n      if (isImportMode) {\n        if (!addProfileItem) throw new Error('Missing profile import handler')\n        await addProfileItem(updatedItem)\n      } else {\n        if (!updateProfileItem) throw new Error('Missing profile update handler')\n        await updateProfileItem(updatedItem)\n        await addProfileUpdater(updatedItem)\n        await mihomoHotReloadConfig()\n      }\n      onClose()\n    } catch (e) {\n      toast.error(String(e))\n    }\n  }\n\n  const selectLocalFile = async (): Promise<void> => {\n    const files = await getFilePath(['yml', 'yaml'])\n    if (!files?.length) return\n\n    const file = await readTextFile(files[0])","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/renderer/src/components/profiles/edit-info-modal.tsx#L45-L81","documentation":"The profile edit-info modal's onSave() branches on import vs edit mode. In import mode it requires the addProfileItem function (typically from a context/hook); if that value is undefined it throws 'Missing profile import handler' instead of calling it. This guard turns an invisible wiring bug (missing provider or prop) into an explicit error.","triggerScenarios":"Opening the edit-info modal to ADD a profile while the component rendering it is outside the provider that supplies addProfileItem (e.g. modal hoisted above the profiles context, or the context hook returning undefined handlers).","commonSituations":"Refactoring modal to render at the root via portal outside <ProfilesProvider>; a context consumer whose value omits addProfileItem; conditional provider mounting (provider not yet mounted when modal submits).","solutions":["Render the modal inside the component tree that provides addProfileItem (inside the profiles context provider).","Check where addProfileItem comes from (useContext/useHook) and confirm the provider wraps the modal's mount point.","Pass the handler explicitly as a prop if context scoping is awkward.","Verify the provider's value object actually includes addProfileItem (not omitted during destructuring)."],"exampleFix":"// before\nif (isImportMode) {\n  if (!addProfileItem) throw new Error('Missing profile import handler')\n// after\n// in the component that owns the modal:\nconst { addProfileItem } = useProfiles() // ensure called inside <ProfilesProvider>\nif (isImportMode && addProfileItem) {\n  await addProfileItem(updatedItem)\n}","handlingStrategy":"type-guard","validationCode":"if (typeof addProfileItem !== 'function') {\n  console.error('edit-info-modal rendered outside ProfilesProvider or provider value incomplete')\n  return\n}","typeGuard":"function hasImportHandler(h: unknown): h is (item: ProfileItem) => Promise<void> {\n  return typeof h === 'function'\n}","tryCatchPattern":"try {\n  if (isImportMode && typeof addProfileItem === 'function') {\n    await addProfileItem(updatedItem)\n  } else if (!isImportMode && typeof updateProfileItem === 'function') {\n    await updateProfileItem(updatedItem)\n  }\n  onClose()\n} catch (e) {\n  notify.error(String(e))\n}","preventionTips":["Render modals inside the provider subtree, not via root portals that escape it.","Destructure context handlers through typed hooks so missing fields surface at typecheck.","Add a dev-mode assertion that context handlers are functions when the modal mounts.","Cover add-profile flow in component tests with the real provider."],"tags":["react","context","missing-handler","ui"],"backgroundTag":"missing-context-handler","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}