hashicorp/vault · warning · Error
Cross-signing a root issuer with itself must be performed ma
Error message
Cross-signing a root issuer with itself must be performed manually using the CLI.
What it means
Thrown by the PKI cross-sign component (ui/lib/pki/addon/components/pki-issuer-cross-sign.js:137) in crossSignIntermediate(). After fetching the target intermediate issuer via pkiReadIssuer, it compares issuer_id against the selected parent issuer; if they are identical the UI refuses because cross-signing a root with itself is not supported in the UI and must be done with the CLI.
Source
Thrown at ui/lib/pki/addon/components/pki-issuer-cross-sign.js:137
...this.formData[row],
hasError: message,
hasUnsupportedParams: error.cause ? error.cause.map((e) => e.message).join(', ') : null,
});
}
}
})
);
@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,View on GitHub (pinned to 744b611b57)
Solutions
- Select a different parent issuer than the intermediate being cross-signed
- If you truly need to self-sign a root, do it manually: vault write pki/root/sign-intermediate ... (or pki issuer sign-intermediate on newer versions)
Example fix
// before: submit, then the action throws
@action
async crossSignIntermediate(intMount, intName, newCrossSignedIssuer) {
const existingIssuer = await this.api.secrets.pkiReadIssuer(intName, intMount);
if (existingIssuer.issuer_id === this.args.parentIssuer.issuer_id) {
throw new Error('Cross-signing a root issuer with itself must be performed manually using the CLI.');
}
...
}
// after: guard in the form and disable self-signing up front
get isSelfSign() {
return this.args.parentIssuer?.issuer_id === this.selectedIntermediate?.issuer_id;
}
// template: <button type="submit" disabled={{this.isSelfSign}}> Defensive patterns
Strategy: validation
Validate before calling
// Before starting the cross-sign flow, require distinct issuers
if (parentIssuer.issuer_id === intermediateIssuer.issuer_id) {
showInlineError('Pick a parent issuer different from the intermediate — self-signing a root must be done via the CLI');
return;
} Type guard
function isSelfSign(parent: { issuer_id: string }, intermediate: { issuer_id: string }): boolean {
return parent.issuer_id === intermediate.issuer_id;
} Try / catch
try {
await this.crossSignIntermediate(mount, intName, newName);
} catch (e) {
if (e.message.includes('must be performed manually using the CLI')) {
notifyUser('Select a different parent issuer, or self-sign via: vault write pki/root/sign-intermediate');
} else {
throw e;
}
} Prevention
- Disable the submit button when both issuer selectors point to the same issuer
- Default the parent dropdown to a value distinct from the selected intermediate
When it happens
Trigger: In the cross-sign issuers workflow, selecting the same issuer as both the intermediate to sign and the parent signing issuer — i.e. attempting to self-sign a root — then submitting.
Common situations: Misconfigured form where both dropdowns end up on the same issuer (default selection overlaps); misunderstanding that the flow needs two distinct issuers.
Related errors
- Certificate must be manually cross-signed using the CLI.
- ${message}. See console for signed ca_chain data.
- A record already exists with the name: ${name}
- Vault expects data to be formatted as an JSON object.
- Missing required query params
AI-assisted analysis of hashicorp/vault@744b611b57 (2026-08-15).
Data as JSON: /api/errors/634ddc589be7b1ef.
Report an issue: GitHub.