{"record":{"id":"62dfa7f685d6e2a3","repo":"hashicorp/vault","slug":"certificate-must-be-manually-cross-signed-using-th","errorCode":null,"errorMessage":"Certificate must be manually cross-signed using the CLI.","messagePattern":"Certificate must be manually cross-signed using the CLI\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"ui/lib/pki/addon/components/pki-issuer-cross-sign.js","lineNumber":145,"sourceCode":"\n  @action\n  async crossSignIntermediate(intMount, intName, newCrossSignedIssuer) {\n    const { parentIssuer } = this.args;\n    // 1. Fetch issuer we want to sign\n    // What/Recovery: any failure is early enough that you can bail safely/normally.\n    const existingIssuer = await this.api.secrets.pkiReadIssuer(intName, intMount);\n\n    // Return if user is attempting to self-sign issuer\n    if (existingIssuer.issuer_id === parentIssuer.issuer_id) {\n      throw new Error('Cross-signing a root issuer with itself must be performed manually using the CLI.');\n    }\n\n    // Translate certificate values to API parameters to pass along: CSR -> Signed CSR -> Cross-Signed issuer\n    // some of these values do not apply to a CSR, but pass anyway. If there is any issue parsing the certificate,\n    // (ex. the certificate contains unsupported values) direct user to manually cross-sign via CLI\n    const certData = parseCertificate(existingIssuer.certificate);\n    if (certData.parsing_errors.length > 0) {\n      throw new Error('Certificate must be manually cross-signed using the CLI.', {\n        cause: certData.parsing_errors,\n      });\n    }\n\n    // 2. Create the new CSR\n    // What/Recovery: any failure is early enough that you can bail safely/normally.\n    const { csr } = await this.api.secrets.pkiGenerateIntermediate('existing', intMount, {\n      key_ref: existingIssuer.key_id,\n      common_name: existingIssuer.common_name,\n      ...certData,\n    });\n    // 3. Sign newCSR with correct parent to create cross-signed cert, \"issuing\"\n    // an intermediate certificate.\n    // What/Recovery: any failure is early enough that you can bail safely/normally.\n    const issuerRef = parentIssuer.issuer_name || parentIssuer.issuer_id;\n    const { ca_chain } = await this.api.secrets.pkiIssuerSignIntermediate(\n      issuerRef,\n      this.secretMountPath.currentPath,","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/hashicorp/vault/blob/744b611b5700b3b7f82d76b4d6938a91b9989367/ui/lib/pki/addon/components/pki-issuer-cross-sign.js#L127-L163","documentation":"Thrown by the PKI cross-sign component (ui/lib/pki/addon/components/pki-issuer-cross-sign.js:145). Before generating a CSR, the component parses the intermediate issuer's certificate with parseCertificate() to translate its values (CN, TTLs, etc.) into API parameters. If the parse reports any parsing_errors, the UI cannot faithfully reproduce the certificate parameters and directs the user to cross-sign manually via the CLI (the original errors are attached as cause).","triggerScenarios":"The intermediate issuer's certificate contains values the UI certificate parser cannot interpret — unusual extensions, exotic key types, or otherwise unsupported fields — so certData.parsing_errors is non-empty.","commonSituations":"Issuers created outside Vault or by older/other CAs with non-standard extensions; certificates using curves or SAN patterns the parser does not model.","solutions":["Follow the message: cross-sign manually with the CLI — generate a CSR (pki/issuer/.../generate-csr or pki_intermediate set-signed workflow), sign it with the parent root, then import the signed bundle","Check the error's cause field for the exact parsing_errors reported by parseCertificate to see which certificate value is unsupported","If the certificate is under your control, reissue it without the offending values and retry the UI flow"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Parse up front and bail with actionable detail instead of mid-flow\nconst certData = parseCertificate(issuer.certificate);\nif (certData.parsing_errors.length > 0) {\n  showManualInstructions(`Certificate values unsupported by the UI: ${certData.parsing_errors.join('; ')}`);\n  return;\n}","typeGuard":"interface ParsedCertificate {\n  parsing_errors: string[];\n  [key: string]: unknown;\n}\nfunction isCleanParse(cert: ParsedCertificate): boolean {\n  return Array.isArray(cert.parsing_errors) && cert.parsing_errors.length === 0;\n}","tryCatchPattern":"try {\n  await this.crossSignIntermediate(mount, intName, newName);\n} catch (e) {\n  if (e.message === 'Certificate must be manually cross-signed using the CLI.') {\n    // e.cause holds the parseError.js parsing_errors array — show it\n    notifyUser(`Cross-sign manually via CLI. Unsupported values: ${e.cause?.join?.('; ')}`);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Pre-parse the certificate and surface parsing_errors before the user invests in the wizard","Issue intermediates with standard values (RSA/EC keys, conventional extensions) so the parser can translate them"],"tags":["pki","cross-signing","certificate-parsing","x509"],"backgroundTag":null,"analyzedSha":"744b611b5700b3b7f82d76b4d6938a91b9989367","analyzedAt":"2026-08-15T14:40:29.333Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}