{"record":{"id":"5c1278ffc96458a5","repo":"mihomo-party-org/clash-party","slug":"subscription-failed-profile-is-not-a-valid-yaml","errorCode":null,"errorMessage":"Subscription failed: Profile is not a valid YAML","messagePattern":"Subscription failed: Profile is not a valid YAML","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/config/profile.ts","lineNumber":409,"sourceCode":"    `Remote profile response url=${redactedUrl} mode=${fetchMode} status=${res.status} contentType=${String(\n      responseHeaders['content-type'] || ''\n    )} bytes=${Buffer.byteLength(data, 'utf8')}`\n  )\n\n  if (res.status < 200 || res.status >= 300) {\n    await profileLogger.warn(\n      `Remote profile request rejected url=${redactedUrl} mode=${fetchMode} status=${res.status}`\n    )\n    throw new Error(`Subscription failed: Request status code ${res.status}`)\n  }\n\n  const decryptedData = await decryptAgeContent(data, options.ageSecretKey, 'subscription')\n  const parsed = parse(decryptedData) as Record<string, unknown> | null\n  if (typeof parsed !== 'object' || parsed === null) {\n    await profileLogger.warn(\n      `Remote profile parse failed url=${redactedUrl} mode=${fetchMode} parsedType=${typeof parsed}`\n    )\n    throw new Error('Subscription failed: Profile is not a valid YAML')\n  }\n  await profileLogger.info(\n    `Remote profile parsed url=${redactedUrl} mode=${fetchMode} summary=${parsedProfileSummary(parsed)}`\n  )\n  if (!parsed['proxies'] && !parsed['proxy-providers']) {\n    await profileLogger.warn(\n      `Remote profile validation failed url=${redactedUrl} mode=${fetchMode} reason=missing-proxies-or-providers summary=${parsedProfileSummary(\n        parsed\n      )}`\n    )\n    throw new Error('Subscription failed: Profile missing proxies or providers')\n  }\n\n  return { data, headers: responseHeaders }\n}\n\nexport async function createProfile(item: Partial<IProfileItem>): Promise<IProfileItem> {\n  const id = item.id || new Date().getTime().toString(16)","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/main/config/profile.ts#L391-L427","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the subscription URL in a browser/curl and confirm it returns a YAML mapping with top-level keys.","Verify the ageSecretKey matches the key the subscription was encrypted with.","Re-import the subscription with a correct URL; check for provider login/captcha pages.","Inspect the warn log line 'Remote profile parse failed url=...' to see parsedType and the fetch mode used."],"exampleFix":"// before\nawait fetchSub(url, { ageSecretKey: 'old-key' })\n// after\n// verify the payload first\ncurl -H 'User-Agent: clash-verge' <url> | head\nawait fetchSub(url, { ageSecretKey: 'correct-key' })","handlingStrategy":"validation","validationCode":"const res = await fetch(url)\nconst text = await res.text()\nif (!text.trim()) throw new Error('subscription body is empty')\nconst parsed = YAML.parse(text)\nif (typeof parsed !== 'object' || parsed === null) {\n  throw new Error('subscription did not return a YAML object')\n}","typeGuard":"function isYamlObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}","tryCatchPattern":"try {\n  await fetchSub(url, { ageSecretKey })\n} catch (e) {\n  if (e.message.includes('Profile is not a valid YAML')) {\n    // verify URL/key, surface a re-import prompt\n  }\n}","preventionTips":["Verify subscription URLs return YAML mappings before saving them.","Keep the ageSecretKey in sync with the provider's encryption key.","Watch for provider auth/captcha responses during automated imports."],"tags":["yaml","subscription","config"],"backgroundTag":"yaml-parse-returned-non-object","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}