{"record":{"id":"cbc8196dd2698c76","repo":"grpc/grpc-go","slug":"input-cert-has-v-uris-but-should-have-1","errorCode":null,"errorMessage":"input cert has %v URIs but should have 1","messagePattern":"input cert has (.+?) URIs but should have 1","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/spiffe/spiffe.go","lineNumber":100,"sourceCode":"\t\treturn nil, fmt.Errorf(\"spiffe: no bundle found for peer certificates trust domain %q but verification with a SPIFFE trust map was configured\", spiffeID.TrustDomain().Name())\n\t}\n\troots := spiffeBundle.X509Authorities()\n\trootPool := x509.NewCertPool()\n\tfor _, root := range roots {\n\t\trootPool.AddCert(root)\n\t}\n\treturn rootPool, nil\n}\n\n// idFromCert parses the SPIFFE ID from the x509.Certificate. If the certificate\n// does not have a valid SPIFFE ID, returns an error.\nfunc idFromCert(cert *x509.Certificate) (*spiffeid.ID, error) {\n\tif cert == nil {\n\t\treturn nil, fmt.Errorf(\"input cert is nil\")\n\t}\n\t// A valid SPIFFE Certificate should have exactly one URI.\n\tif len(cert.URIs) != 1 {\n\t\treturn nil, fmt.Errorf(\"input cert has %v URIs but should have 1\", len(cert.URIs))\n\t}\n\tid, err := spiffeid.FromURI(cert.URIs[0])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid spiffeid: %v\", err)\n\t}\n\treturn &id, nil\n}\n","sourceCodeStart":82,"sourceCodeEnd":108,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/credentials/spiffe/spiffe.go#L82-L108","documentation":"Raised by idFromCert when len(cert.URIs) != 1. A conformant SPIFFE leaf certificate must carry exactly one URI SAN holding the SPIFFE ID; zero URIs or two-or-more URIs both violate the spec and are rejected.","triggerScenarios":"A cert with no URI SAN (traditional cert); a cert with two URI SANs (e.g. a spiffe:// URI plus an http:// metadata URI); a cert generator that attaches the SPIFFE ID alongside other URIs.","commonSituations":"Using a general-purpose CA that adds extra URI SANs; service mesh issuing a cert with both SPIFFE and non-SPIFFE URIs; legacy cert with only DNS SANs presented where SPIFFE verification is configured.","solutions":["Re-issue the certificate so the URI SAN list contains exactly one entry, the spiffe:// URI.","Move any non-SPIFFE URIs to a different SAN type or a custom extension.","Confirm the CA (SPIRE/workload registrar) is configured to emit a single URI SAN.","Inspect with: openssl x509 -text -noout | grep -A2 'URI:'."],"exampleFix":"// before: cert URIs = [spiffe://example.org/svc, https://svc/metrics]\n// after: cert URIs = [spiffe://example.org/svc]","handlingStrategy":"type-guard","validationCode":"func hasOneURISAN(c *x509.Certificate) bool { return c != nil && len(c.URIs) == 1 }","typeGuard":"func isSingleURISpiffeCert(c *x509.Certificate) bool {\n    return c != nil && len(c.URIs) == 1\n}","tryCatchPattern":"In your verifier, after parsing the leaf, assert len(leaf.URIs)==1; if not, reject with a message naming the actual count before the SPIFFE helper does.","preventionTips":["Configure your CA/SPIRE to emit exactly one URI SAN per workload cert.","Audit issued certs periodically for URI SAN count.","Keep non-SPIFFE URIs out of workload cert templates."],"tags":["grpc","spiffe","tls","certificates","san","security"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}