mihomo-party-org/clash-party · error

Subscription failed: Profile missing proxies or providers

Error message

Subscription failed: Profile missing proxies or providers

What it means

After successfully parsing the remote subscription into an object, fetchAndValidateSubscription requires at least one of the top-level keys 'proxies' or 'proxy-providers'. A valid YAML object lacking both is rejected with 'Profile missing proxies or providers' so an empty or invalid config never replaces an existing profile.

Source

Thrown at src/main/config/profile.ts:420

  const decryptedData = await decryptAgeContent(data, options.ageSecretKey, 'subscription')
  const parsed = parse(decryptedData) as Record<string, unknown> | null
  if (typeof parsed !== 'object' || parsed === null) {
    await profileLogger.warn(
      `Remote profile parse failed url=${redactedUrl} mode=${fetchMode} parsedType=${typeof parsed}`
    )
    throw new Error('Subscription failed: Profile is not a valid YAML')
  }
  await profileLogger.info(
    `Remote profile parsed url=${redactedUrl} mode=${fetchMode} summary=${parsedProfileSummary(parsed)}`
  )
  if (!parsed['proxies'] && !parsed['proxy-providers']) {
    await profileLogger.warn(
      `Remote profile validation failed url=${redactedUrl} mode=${fetchMode} reason=missing-proxies-or-providers summary=${parsedProfileSummary(
        parsed
      )}`
    )
    throw new Error('Subscription failed: Profile missing proxies or providers')
  }

  return { data, headers: responseHeaders }
}

export async function createProfile(item: Partial<IProfileItem>): Promise<IProfileItem> {
  const id = item.id || new Date().getTime().toString(16)
  const newItem: IProfileItem = {
    id,
    name: item.name || (item.type === 'remote' ? 'Remote File' : 'Local File'),
    type: item.type || 'local',
    url: item.url,
    substore: item.substore || false,
    interval: item.interval || 0,
    override: item.override || [],
    useProxy: item.useProxy || false,
    allowFixedInterval: item.allowFixedInterval || false,
    autoUpdate: item.autoUpdate ?? false,

View on GitHub (pinned to 911e090537)

Solutions

  1. Check the downloaded YAML contains top-level 'proxies:' or 'proxy-providers:'; fix the subscription source.
  2. Confirm the URL targets a Clash/mihomo-format config, not another proxy client's format.
  3. Use a subscription converter (e.g. subconverter) to translate the provider output to Clash format.
  4. Re-run fetchSub after updating; check the warn log 'reason=missing-proxies-or-providers' plus the summary field.

Example fix

// before (subscription content)
rules:
  - MATCH,DIRECT
// after
proxies:
  - name: node1
    type: ss
    server: example.com
    port: 443
rules:
  - MATCH,DIRECT
Defensive patterns

Strategy: validation

Validate before calling

const parsed = YAML.parse(text)
if (typeof parsed !== 'object' || parsed === null) throw new Error('not an object')
if (!parsed['proxies'] && !parsed['proxy-providers']) {
  throw new Error('config has no proxies or proxy-providers')
}

Type guard

function hasProxies(c: unknown): c is { proxies?: unknown[]; 'proxy-providers'?: unknown } {
  return typeof c === 'object' && c !== null &&
    ('proxies' in c || 'proxy-providers' in c)
}

Try / catch

try {
  await fetchSub(url, options)
} catch (e) {
  if (e.message.includes('missing proxies or providers')) {
    // convert the subscription to Clash format or fix the source
  }
}

Prevention

When it happens

Trigger: fetchSub returns parsed YAML that is an object but has neither 'proxies' nor 'proxy-providers' keys — e.g. a config with only rules, or a payload like `{}` after decryption.

Common situations: Provider serves a partial/empty template; user pointed the subscription at a Clash config variant without proxies (e.g. rules-only override file); provider mistakenly serves Surge/Quantumult configs with different schema.

Related errors


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