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

Missing profile update handler

Error message

Missing profile update handler

What it means

The edit branch of onSave() requires updateProfileItem; if it is undefined the modal throws 'Missing profile update handler'. Same pattern as the import-mode guard: the context providing profile mutation functions is missing or incomplete when the user saves an EDITED profile.

Source

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

  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])
    const fileName = files[0].split('/').pop()?.split('\\').pop()
    setValues({
      ...values,

View on GitHub (pinned to 911e090537)

Solutions

  1. Ensure the modal is a descendant of the context provider that defines updateProfileItem.
  2. Inspect the provider's value and confirm updateProfileItem is included.
  3. Pass updateProfileItem via props as an explicit alternative to context.
  4. Check for provider unmount during async save and stabilize the provider placement.

Example fix

// before
if (!updateProfileItem) throw new Error('Missing profile update handler')
// after
const { updateProfileItem } = useProfilesContext()
if (!updateProfileItem) throw new Error('Missing profile update handler') // now only fires on real wiring bugs
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof updateProfileItem !== 'function') {
  console.error('edit-info-modal: updateProfileItem missing — check provider wiring')
  return
}

Type guard

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

Try / catch

try {
  if (typeof updateProfileItem === 'function') {
    await updateProfileItem(updatedItem)
    await addProfileUpdater(updatedItem)
    await mihomoHotReloadConfig()
    onClose()
  }
} catch (e) {
  notify.error(String(e))
}

Prevention

When it happens

Trigger: Submitting an edit of an existing profile while the modal is rendered outside the provider supplying updateProfileItem, or the context value was constructed without that function.

Common situations: Portal-rendered modal above the provider; hook rename/refactor left the provider value without updateProfileItem; provider conditionally unmounted during save (e.g. modal triggers state change that unmounts provider).

Related errors


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