microsoft/aspire · error · InvalidOperationException

Unknown issuer spec type

Error message

Unknown issuer spec type '{issuer.Spec?.GetType().Name}' on issuer '{issuer.Name}'.

What it means

BuildClusterIssuerManifestAsync switches on the concrete type of issuer.Spec to render the manifest; the default arm throws InvalidOperationException for any Spec type the publisher does not know how to serialize. This indicates either a newer/unknown spec type was configured or a custom spec object was attached.

Solutions

  1. Use only the built-in configuration methods (WithLetsEncryptProduction/Staging, WithAcmeServer) that set supported spec types.
  2. If you wrote a custom spec type, add support for it in manifest generation or switch to a supported one.
  3. Check package versions so the spec types match the publisher's expectations.

Example fix

// before
issuer.Spec = new MyCustomAcmeSpec();

// after
issuerBuilder.WithAcmeServer(new Uri("https://acme.example.com/directory"), email);
Defensive patterns

Strategy: type-guard

Validate before calling

if (issuer.Spec is not (null or KnownAcmeSpec)) throw new InvalidOperationException("Unsupported issuer spec type");

Type guard

bool IsSupportedSpec(object? spec) => spec is null or KnownAcmeSpec;

Try / catch

try { await manifestBuilder.BuildAsync(); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Unknown issuer spec type")) { /* switch to built-in config methods */ throw; }

Prevention

When it happens

Trigger: issuer.Spec holds a type outside the supported set (e.g. a custom ACME spec variant or a spec from a different cert-manager library version) when the manifest is being generated during publish.

Common situations: Upgrading Aspire or mixing custom CertManagerIssuerResource spec implementations, or writing a custom extension that sets an unsupported Spec type.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/98e46022f484e104. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Kubernetes/CertManagerExtensions.cs:598

        {
            case CertManagerAcmeIssuerSpec acme:
                {
                    var server = await acme.ServerUrl.GetValueAsync(cancellationToken).ConfigureAwait(false);
                    var email = await acme.Email.GetValueAsync(cancellationToken).ConfigureAwait(false);
                    sb.AppendLine("  acme:");
                    sb.Append("    server: ").AppendLine(server);
                    sb.Append("    email: ").AppendLine(email);
                    sb.AppendLine("    privateKeySecretRef:");
                    sb.Append("      name: ").Append(k8sIssuerName).AppendLine("-account-key");
                    sb.AppendLine("    solvers:");
                    foreach (var solver in issuer.Solvers)
                    {
                        AppendSolver(sb, solver, model, certManager, issuer, logger);
                    }
                    break;
                }
            default:
                throw new InvalidOperationException(
                    $"Unknown issuer spec type '{issuer.Spec?.GetType().Name}' on issuer '{issuer.Name}'.");
        }

        return sb.ToString();
    }

    private static void AppendSolver(
        StringBuilder sb,
        CertManagerSolverConfig solver,
        ApplicationModel.DistributedApplicationModel model,
        CertManagerResource certManager,
        CertManagerIssuerResource issuer,
        ILogger logger)
    {
        switch (solver)
        {
            case CertManagerHttp01SolverConfig:
                {

View on GitHub (pinned to 25830f84bd)