dapr/dapr · critical · VerificationError

failed to extract SPIFFE ID: %w

Error message

failed to extract SPIFFE ID: %w

What it means

verifyCertAppIdentity parsed the certificate chain but go-spiffe's x509svid.IDFromCert could not extract a SPIFFE ID from the leaf. Typically the leaf has no URI SAN (or a malformed one), meaning it is not a SPIFFE SVID at all — for example a plain TLS cert was used for workflow signing. Wrapped as 'signing certificate N: failed to extract SPIFFE ID' in the VerificationError.

Source

Thrown at pkg/runtime/wfengine/state/state.go:1203

	if expectedNamespace == "" {
		return errors.New("expectedNamespace must not be empty")
	}
	if len(certChainDER) == 0 {
		return errors.New("certificate chain is empty")
	}

	certs, err := x509.ParseCertificates(certChainDER)
	if err != nil {
		return fmt.Errorf("failed to parse certificate chain: %w", err)
	}
	if len(certs) == 0 {
		return errors.New("no certificates in chain")
	}

	leaf := certs[0]
	spiffeID, err := x509svid.IDFromCert(leaf)
	if err != nil {
		return fmt.Errorf("failed to extract SPIFFE ID: %w", err)
	}

	// Validate the full SPIFFE path structure: /ns/<namespace>/<app-id>
	// Split produces: ["", "ns", "<namespace>", "<app-id>"]
	segments := strings.Split(spiffeID.Path(), "/")
	if len(segments) != 4 || segments[0] != "" || segments[1] != "ns" || segments[2] == "" || segments[3] == "" {
		return fmt.Errorf("SPIFFE ID %q does not match expected path format /ns/<namespace>/<app-id>", spiffeID)
	}
	certNamespace := segments[2]
	certAppID := segments[3]

	if certNamespace != expectedNamespace {
		return fmt.Errorf("certificate SPIFFE ID namespace %q does not match expected namespace %q", certNamespace, expectedNamespace)
	}
	if certAppID != expectedAppID {
		return fmt.Errorf("certificate SPIFFE ID app %q does not match expected app %q", certAppID, expectedAppID)
	}

View on GitHub (pinned to 74ad417027)

Solutions

  1. Issue signing certificates as proper SPIFFE SVIDs (URI SAN spiffe://<trust-domain>/...) via the workload identity/sentry subsystem
  2. Re-create the workflow so it is signed by the SVID-based identity
  3. Verify the leaf really is the SVID and not an intermediate/CA placed first by mistake

Example fix

// before: plain TLS cert (no URI SAN) used as signing identity
leaf := tlsCert.Leaf // CN=myapp, no SPIFFE URI SAN

// after: obtain an SVID from the workload identity subsystem
// leaf must carry URI SAN: spiffe://example.org/ns/production/orders
svid := workloadAPI.FetchX509SVID()
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the signing identity is a real SVID before use
if _, err := x509svid.IDFromCert(leaf); err != nil {
	return fmt.Errorf("signing cert is not a SPIFFE SVID (missing URI SAN): %w", err)
}

Type guard

func isSPIFFEExtractionFailure(err error) bool {
	var ver *wferrors.VerificationError
	return errors.As(err, &ver) && strings.Contains(ver.Error(), "failed to extract SPIFFE ID")
}

Try / catch

if err := loadAndVerify(); err != nil {
	var ver *wferrors.VerificationError
	if errors.As(err, &ver) && strings.Contains(ver.Error(), "failed to extract SPIFFE ID") {
		// a non-SVID cert was used for signing: re-issue from the workload identity subsystem and recreate
	}
	return err
}

Prevention

When it happens

Trigger: The leaf certificate in the stored chain lacks a valid spiffe:// URI SAN — issuing workflow signing certs from a CA that does not embed SPIFFE IDs, or using an ordinary TLS certificate as the signing identity.

Common situations: Custom/internal CA without SPIFFE support wired into the signing path instead of the workload identity system; cert rotation switching from SVIDs to plain certs; test setups using self-signed TLS certs.

Related errors


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/22e40296f8edd783. Report an issue: GitHub.