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

Missing profile import handler

Error message

Missing profile import handler

What it means

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.

Source

Thrown at src/renderer/src/components/profiles/edit-info-modal.tsx:63

    ...item
  })
  const inputWidth = 'w-[400px] md:w-[400px] lg:w-[600px] xl:w-[800px]'
  const { t } = useTranslation()
  const isImportMode = mode === 'import'
  const canSave =
    !isImportMode || (values.type === 'remote' ? Boolean(values.url?.trim()) : values.file != null)

  const onSave = async (): Promise<void> => {
    try {
      const updatedItem = {
        ...values,
        override: values.override?.filter(
          (i) =>
            overrideItems.find((t) => t.id === i) && !overrideItems.find((t) => t.id === i)?.global
        )
      }
      if (isImportMode) {
        if (!addProfileItem) throw new Error('Missing profile import handler')
        await addProfileItem(updatedItem)
      } else {
        if (!updateProfileItem) throw new Error('Missing profile update handler')
        await updateProfileItem(updatedItem)
        await addProfileUpdater(updatedItem)
        await mihomoHotReloadConfig()
      }
      onClose()
    } catch (e) {
      toast.error(String(e))
    }
  }

  const selectLocalFile = async (): Promise<void> => {
    const files = await getFilePath(['yml', 'yaml'])
    if (!files?.length) return

    const file = await readTextFile(files[0])

View on GitHub (pinned to 911e090537)

Solutions

  1. Render the modal inside the component tree that provides addProfileItem (inside the profiles context provider).
  2. Check where addProfileItem comes from (useContext/useHook) and confirm the provider wraps the modal's mount point.
  3. Pass the handler explicitly as a prop if context scoping is awkward.
  4. Verify the provider's value object actually includes addProfileItem (not omitted during destructuring).

Example fix

// before
if (isImportMode) {
  if (!addProfileItem) throw new Error('Missing profile import handler')
// after
// in the component that owns the modal:
const { addProfileItem } = useProfiles() // ensure called inside <ProfilesProvider>
if (isImportMode && addProfileItem) {
  await addProfileItem(updatedItem)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof addProfileItem !== 'function') {
  console.error('edit-info-modal rendered outside ProfilesProvider or provider value incomplete')
  return
}

Type guard

function hasImportHandler(h: unknown): h is (item: ProfileItem) => Promise<void> {
  return typeof h === 'function'
}

Try / catch

try {
  if (isImportMode && typeof addProfileItem === 'function') {
    await addProfileItem(updatedItem)
  } else if (!isImportMode && typeof updateProfileItem === 'function') {
    await updateProfileItem(updatedItem)
  }
  onClose()
} catch (e) {
  notify.error(String(e))
}

Prevention

When it happens

Trigger: 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).

Common situations: 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).

Related errors


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