denoland/deno · error · AnyError

No certificate chain returned

Error message

No certificate chain returned

What it means

To sign provenance, Deno requests a short-lived certificate from Fulcio; the response must contain either `signedCertificateEmbeddedSct` or `signedCertificateDetachedSct`. When the JSON body parses but both fields are missing, there is no certificate chain to build the attestation with, and this error aborts the publish. It indicates an unexpected/empty payload from the CA endpoint rather than misuse on your side.

Solutions

  1. Re-run `deno publish` — the certificate request is per-run and transient upstream issues resolve themselves; the failed publish left no partial state on jsr.io.
  2. Check Sigstore status (status.sigstore.dev) for active Fulcio incidents before retrying in a loop.
  3. Bypass TLS-intercepting corporate proxies for api.sigstore.dev / fulcio.sigstore.dev, which can corrupt JSON bodies.
  4. If reproducible, drop `--provenance` to unblock the release and investigate separately.
Defensive patterns

Strategy: retry

Try / catch

for (let attempt = 1; attempt <= 3; attempt++) {
  try {
    await runDeno(['publish', '--provenance']);
    break;
  } catch (e) {
    if (String(e.message).includes('No certificate chain returned') && attempt < 3) {
      await delay(15_000);
      continue; // Fulcio hiccup; new signing attempt on the next run
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: `deno publish --provenance` where Fulcio responds with a structurally valid but empty signing response (outage or API change); a proxy/GHE mirror returning an error page that deserialized into default-empty fields; transient infrastructure hiccup during the signing leg.

Common situations: One-off CI publish failures that pass on retry; Sigstore/Fulcio incidents; environments with TLS-intercepting proxies altering responses. Local misconfiguration cannot cause this — only the network path and upstream.

Understand the failure class

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/9e340d2a3e4aeeb2. Report an issue: GitHub.

Appendix: source

Thrown at cli/tools/publish/provenance.rs:531

          content: public_key,
        },
        proof_of_possession: BASE64_STANDARD.encode(challenge.as_ref()),
      },
    };

    let response = self
      .http_client
      .post_json(url.parse()?, &request_body)?
      .send()
      .await?;

    let body: SigningCertificateResponse =
      http_util::body_to_json(response).await?;

    let key = body
      .signed_certificate_embedded_sct
      .or(body.signed_certificate_detached_sct)
      .ok_or_else(|| anyhow::anyhow!("No certificate chain returned"))?;
    Ok(key.chain.certificates)
  }

  async fn gha_request_token(&self, aud: &str) -> Result<String, AnyError> {
    let Ok(req_url) = env::var("ACTIONS_ID_TOKEN_REQUEST_URL") else {
      bail!("Not running in GitHub Actions");
    };

    let Some(token) = gha_oidc_token() else {
      bail!("No OIDC token available");
    };

    let mut url = req_url.parse::<Url>()?;
    url.query_pairs_mut().append_pair("audience", aud);
    let res_bytes = self
      .http_client
      .get(url)?
      .header(

View on GitHub (pinned to 9ad36f7a2c)