hashicorp/vault · warning · Error
Certificate must be manually cross-signed using the CLI.
Error message
Certificate must be manually cross-signed using the CLI.
What it means
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).
Source
Thrown at ui/lib/pki/addon/components/pki-issuer-cross-sign.js:145
@action
async crossSignIntermediate(intMount, intName, newCrossSignedIssuer) {
const { parentIssuer } = this.args;
// 1. Fetch issuer we want to sign
// What/Recovery: any failure is early enough that you can bail safely/normally.
const existingIssuer = await this.api.secrets.pkiReadIssuer(intName, intMount);
// Return if user is attempting to self-sign issuer
if (existingIssuer.issuer_id === parentIssuer.issuer_id) {
throw new Error('Cross-signing a root issuer with itself must be performed manually using the CLI.');
}
// Translate certificate values to API parameters to pass along: CSR -> Signed CSR -> Cross-Signed issuer
// some of these values do not apply to a CSR, but pass anyway. If there is any issue parsing the certificate,
// (ex. the certificate contains unsupported values) direct user to manually cross-sign via CLI
const certData = parseCertificate(existingIssuer.certificate);
if (certData.parsing_errors.length > 0) {
throw new Error('Certificate must be manually cross-signed using the CLI.', {
cause: certData.parsing_errors,
});
}
// 2. Create the new CSR
// What/Recovery: any failure is early enough that you can bail safely/normally.
const { csr } = await this.api.secrets.pkiGenerateIntermediate('existing', intMount, {
key_ref: existingIssuer.key_id,
common_name: existingIssuer.common_name,
...certData,
});
// 3. Sign newCSR with correct parent to create cross-signed cert, "issuing"
// an intermediate certificate.
// What/Recovery: any failure is early enough that you can bail safely/normally.
const issuerRef = parentIssuer.issuer_name || parentIssuer.issuer_id;
const { ca_chain } = await this.api.secrets.pkiIssuerSignIntermediate(
issuerRef,
this.secretMountPath.currentPath,View on GitHub (pinned to 744b611b57)
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
Defensive patterns
Strategy: validation
Validate before calling
// Parse up front and bail with actionable detail instead of mid-flow
const certData = parseCertificate(issuer.certificate);
if (certData.parsing_errors.length > 0) {
showManualInstructions(`Certificate values unsupported by the UI: ${certData.parsing_errors.join('; ')}`);
return;
} Type guard
interface ParsedCertificate {
parsing_errors: string[];
[key: string]: unknown;
}
function isCleanParse(cert: ParsedCertificate): boolean {
return Array.isArray(cert.parsing_errors) && cert.parsing_errors.length === 0;
} Try / catch
try {
await this.crossSignIntermediate(mount, intName, newName);
} catch (e) {
if (e.message === 'Certificate must be manually cross-signed using the CLI.') {
// e.cause holds the parseError.js parsing_errors array — show it
notifyUser(`Cross-sign manually via CLI. Unsupported values: ${e.cause?.join?.('; ')}`);
} else {
throw e;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Issuers created outside Vault or by older/other CAs with non-standard extensions; certificates using curves or SAN patterns the parser does not model.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Cross-signing a root issuer with itself must be performed ma
- ${message}. See console for signed ca_chain data.
AI-assisted analysis of hashicorp/vault@744b611b57 (2026-08-15).
Data as JSON: /api/errors/62dfa7f685d6e2a3.
Report an issue: GitHub.