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.
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).
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
- 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.
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
- Missing profile update handler
- useAppConfig must be used within an AppConfigProvider
- useConfig must be used within Provider
- useControledMihomoConfig must be used within a…
- useGroups must be used within an GroupsProvider
AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30).
Data as JSON: /api/errors/be1a9e96a7d1722c.
Report an issue: GitHub.
Appendix: 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)