mihomo-party-org/clash-party · error

Plugin URL must use https

Error message

Plugin URL must use https

What it means

After parsing succeeds, parseDownloadUrl requires the protocol to be exactly https:. Any other scheme (http:, ftp:, file:) is rejected with 'Plugin URL must use https' to guarantee plugin downloads are fetched over TLS.

Source

Thrown at src/main/resolve/plugin/remote.ts:13

import { getAppConfig } from '../../config/app'
import { MAX_PLUGIN_FILE_BYTES } from './constants'
import { requestOnce } from './http-client'
import { createGuardedLookup, isForbiddenHost } from './net-guard'

function parseDownloadUrl(url: string): URL {
  let parsed: URL
  try {
    parsed = new URL(url)
  } catch {
    throw new Error('Invalid plugin URL')
  }
  if (parsed.protocol !== 'https:') throw new Error('Plugin URL must use https')
  if (parsed.username || parsed.password) throw new Error('Plugin URL must not contain userinfo')
  if (parsed.hash) throw new Error('Plugin URL must not contain a fragment')
  if (isForbiddenHost(parsed.hostname)) throw new Error('Plugin URL must use a public host')
  return parsed
}

export async function fetchRemotePlugin(url: string): Promise<string> {
  const parsed = parseDownloadUrl(url)
  const { subscriptionTimeout = 30000, pluginUseProxy } = await getAppConfig()
  let proxy: { host: string; port: number } | undefined
  if (pluginUseProxy) {
    const { getControledMihomoConfig } = await import('../../config/controledMihomo')
    const { 'mixed-port': port = 7890 } = await getControledMihomoConfig()
    proxy = { host: '127.0.0.1', port }
  }

  const response = await requestOnce(parsed.toString(), {
    method: 'GET',

View on GitHub (pinned to 911e090537)

Solutions

  1. Switch the source to an https:// URL (use https mirror or CDN link).
  2. Upgrade an internal http server to TLS, or use an https reverse proxy.
  3. If the content is local, install it through the local-file plugin path instead of fetchRemotePlugin.

Example fix

// before
await fetchRemotePlugin('http://mirror.example.com/plugin.yaml')
// after
await fetchRemotePlugin('https://mirror.example.com/plugin.yaml')
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(input)
if (u.protocol !== 'https:') throw new Error('download URL must start with https://')

Type guard

const isHttpsUrl = (s: string): boolean => {
  try { return new URL(s).protocol === 'https:' } catch { return false }
}

Try / catch

try {
  await fetchRemotePlugin(input)
} catch (e) {
  if (e.message === 'Plugin URL must use https') {
    showUrlInputError('Only https:// download links are supported')
  } else throw e
}

Prevention

When it happens

Trigger: Passing a download URL whose protocol is not https — most commonly an http:// mirror link, or a file:// URL for a local file.

Common situations: Old or internal mirror links still using http; user pastes a local file:// path; copying an insecure download link from docs.

Related errors


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