{"record":{"id":"6ce6e8ecfbab7dab","repo":"CherryHQ/cherry-studio","slug":"invalid-pem-format-missing-begin-end-markers-or-k","errorCode":null,"errorMessage":"Invalid PEM format: missing BEGIN/END markers or key content","messagePattern":"Invalid PEM format: missing BEGIN/END markers or key content","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/aiCore/src/core/providers/core/utils.ts","lineNumber":61,"sourceCode":"  let foundBegin = false\n  let foundEnd = false\n\n  for (const line of lines) {\n    if (line === '-----BEGIN PRIVATE KEY-----') {\n      foundBegin = true\n      continue\n    }\n    if (line === '-----END PRIVATE KEY-----') {\n      foundEnd = true\n      break\n    }\n    if (foundBegin && !foundEnd) {\n      keyContent += line\n    }\n  }\n\n  if (!foundBegin || !foundEnd || !keyContent) {\n    throw new Error('Invalid PEM format: missing BEGIN/END markers or key content')\n  }\n\n  // 重新格式化为 64 字符一行\n  const formattedContent = keyContent.match(/.{1,64}/g)?.join('\\n') || keyContent\n\n  return `-----BEGIN PRIVATE KEY-----\\n${formattedContent}\\n-----END PRIVATE KEY-----`\n}\n\n/**\n * 重新构建 PEM 私钥\n */\nfunction reconstructPemKey(key: string): string {\n  // 移除所有空白字符和可能存在的不完整头尾\n  let cleanKey = key.replace(/\\s+/g, '')\n  cleanKey = cleanKey.replace(/-----BEGIN[^-]*-----/g, '')\n  cleanKey = cleanKey.replace(/-----END[^-]*-----/g, '')\n\n  // 确保私钥内容不为空","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/aiCore/src/core/providers/core/utils.ts#L43-L79","documentation":"normalizePemFormat runs when the input already contains both BEGIN and END markers. It scans lines between the markers to extract key content; if it never sees a clean BEGIN/END pair or finds no content lines, the PEM is structurally broken and it throws. This catches malformed markers (e.g. extra text, wrong marker name, duplicated headers).","triggerScenarios":"The key string contains '-----BEGIN PRIVATE KEY-----' and '-----END PRIVATE KEY-----' substrings but the line-by-line scan fails: markers glued onto base64 content, wrong marker type, or content only on the same line as the marker.","commonSituations":"A PEM where BEGIN/END are not on their own lines (minified); markers for a different key type pasted in (e.g. EC PRIVATE KEY with PRIVATE KEY markers expected); copy-paste that merged lines; a key with stray whitespace/quotes breaking exact line equality.","solutions":["Re-export the key in standard PEM format with markers on their own lines.","Strip surrounding quotes and normalize newlines before calling formatPrivateKey.","If the key uses a different header (e.g. RSA PRIVATE KEY), convert it to PKCS#8 'PRIVATE KEY' format first."],"exampleFix":"// before — markers glued to content\nformatPrivateKey('-----BEGIN PRIVATE KEY-----MIIEvQ...-----END PRIVATE KEY-----')\n// after — proper newlines (or let reconstructPemKey rebuild by removing the markers first)\nformatPrivateKey('-----BEGIN PRIVATE KEY-----\\nMIIEvQ...\\n-----END PRIVATE KEY-----')","handlingStrategy":"validation","validationCode":"function looksLikeValidPem(key: string): boolean {\n  const lines = key.split('\\n').map((l) => l.trim()).filter(Boolean)\n  return lines[0] === '-----BEGIN PRIVATE KEY-----' && lines[lines.length - 1] === '-----END PRIVATE KEY-----' && lines.length > 2\n}\nif (!looksLikeValidPem(privateKey)) throw new Error('PEM markers must be on their own lines')\nformatPrivateKey(privateKey)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Re-export keys in standard PEM with markers on their own lines.","Normalize newlines and strip quotes before calling formatPrivateKey.","Convert non-PKCS#8 headers to 'PRIVATE KEY' format first."],"tags":["auth","private-key","pem","validation"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}