mihomo-party-org/clash-party · error

i18next.t('profiles.error.urlParamMissing')

Error message

i18next.t('profiles.error.urlParamMissing')

What it means

This is an application-level error thrown by handleDeepLink in src/main/deeplink.ts:25 when a deeplink URL targeting the 'install-config' host is missing its required 'url' query parameter. The code reads urlObj.searchParams.get('url') and throws before attempting to add the profile, because addProfileItem with type 'remote' cannot proceed without a profile URL. The message is an i18next key ('profiles.error.urlParamMissing') resolved to a localized user-facing string.

Source

Thrown at src/main/deeplink.ts:25

export function findDeepLink(args: string[]): string | undefined {
  return args.find((arg) => {
    const lower = arg.toLowerCase()
    return lower.startsWith('clash://') || lower.startsWith('mihomo://')
  })
}

export async function handleDeepLink(url: string): Promise<void> {
  if (!findDeepLink([url])) return

  const urlObj = new URL(url)
  switch (urlObj.host) {
    case 'install-config': {
      try {
        const profileUrl = urlObj.searchParams.get('url')
        const profileName = urlObj.searchParams.get('name')
        if (!profileUrl) {
          throw new Error(i18next.t('profiles.error.urlParamMissing'))
        }
        await addProfileItem({
          type: 'remote',
          name: profileName ?? undefined,
          url: profileUrl
        })
        mainWindow?.webContents.send('profileConfigUpdated')
        new Notification({ title: i18next.t('profiles.notification.importSuccess') }).show()
      } catch (e) {
        safeShowErrorBox('profiles.error.importFailed', `${url}\n${e}`)
      }
      break
    }
    case 'install-plugin': {
      let plugin: IPluginItem
      try {
        const pluginUrl = urlObj.searchParams.get('url')
        if (!pluginUrl) {

View on GitHub (pinned to 911e090537)

Solutions

  1. Add a valid url query parameter to the deeplink, e.g. clash://install-config?url=https%3A%2F%2Fexample.com%2Fprofile.yaml
  2. Ensure the url parameter is URL-encoded (encodeURIComponent) when constructing the deeplink so it is not dropped or split
  3. If the link comes from a QR code or shared text, verify it was not truncated before the query string
  4. In handleDeepLink, catch this error and show a localized error box instead of crashing (the sibling install-plugin branch already does safeShowErrorBox)

Example fix

// before
const link = 'clash://install-config?name=myprofile'
// after
const url = encodeURIComponent('https://example.com/profile.yaml')
const link = `clash://install-config?url=${url}&name=myprofile`
Defensive patterns

Strategy: validation

Validate before calling

const url = new URL(rawLink)
const profileUrl = url.searchParams.get('url')
if (!profileUrl) {
  throw new Error(i18next.t('profiles.error.urlParamMissing'))
}

Type guard

function hasInstallConfigUrl(link: string): link is string & { __brand: 'validInstallConfig' } {
  try {
    return !!new URL(link).searchParams.get('url')
  } catch {
    return false
  }
}

Try / catch

try {
  await handleDeepLink(link)
} catch (e) {
  if (String(e).includes('urlParamMissing') || e instanceof Error) {
    safeShowErrorBox('profiles.error.urlParamMissing', `${e}`)
  }
}

Prevention

When it happens

Trigger: Handling a deeplink like clash://install-config?name=foo without ?url=..., or with url= (empty value, since searchParams.get returns '' which is falsy and fails the !profileUrl check).

Common situations: Users copy/paste truncated subscription links from web pages; marketing sites generate deeplinks with missing or empty url params; URL encoding strips the parameter; bots or scripts invoke the deeplink scheme programmatically without the full query string.

Related errors


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