mihomo-party-org/clash-party · error

Subscription failed: Profile is not a valid YAML

Error message

Subscription failed: Profile is not a valid YAML

What it means

fetchAndValidateSubscription fetches a remote profile, decrypts it with the Age key, and parses the plaintext as YAML. If `parse` returns null or a non-object (string, number, boolean), the function logs the failure and throws 'Subscription failed: Profile is not a valid YAML'. This means the decrypted payload was not a YAML mapping, so the content cannot become a mihomo profile.

Source

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

    `Remote profile response url=${redactedUrl} mode=${fetchMode} status=${res.status} contentType=${String(
      responseHeaders['content-type'] || ''
    )} bytes=${Buffer.byteLength(data, 'utf8')}`
  )

  if (res.status < 200 || res.status >= 300) {
    await profileLogger.warn(
      `Remote profile request rejected url=${redactedUrl} mode=${fetchMode} status=${res.status}`
    )
    throw new Error(`Subscription failed: Request status code ${res.status}`)
  }

  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)

View on GitHub (pinned to 911e090537)

Solutions

  1. Open the subscription URL in a browser/curl and confirm it returns a YAML mapping with top-level keys.
  2. Verify the ageSecretKey matches the key the subscription was encrypted with.
  3. Re-import the subscription with a correct URL; check for provider login/captcha pages.
  4. Inspect the warn log line 'Remote profile parse failed url=...' to see parsedType and the fetch mode used.

Example fix

// before
await fetchSub(url, { ageSecretKey: 'old-key' })
// after
// verify the payload first
curl -H 'User-Agent: clash-verge' <url> | head
await fetchSub(url, { ageSecretKey: 'correct-key' })
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(url)
const text = await res.text()
if (!text.trim()) throw new Error('subscription body is empty')
const parsed = YAML.parse(text)
if (typeof parsed !== 'object' || parsed === null) {
  throw new Error('subscription did not return a YAML object')
}

Type guard

function isYamlObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v)
}

Try / catch

try {
  await fetchSub(url, { ageSecretKey })
} catch (e) {
  if (e.message.includes('Profile is not a valid YAML')) {
    // verify URL/key, surface a re-import prompt
  }
}

Prevention

When it happens

Trigger: Calling fetchSub/fetchAndValidateSubscription when the remote subscription (after Age decryption with the supplied ageSecretKey) yields YAML that parses to null or a scalar — e.g. an empty body, a plain string, or `null` document.

Common situations: Subscription URL returns empty body or plain text (auth/captcha page stored as text); wrong or stale ageSecretKey causing decryption to produce garbage that parses to a non-object; provider returning a bare value like a token string instead of YAML config.

Related errors


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