apache/shenyu · error · ShenyuException
At least one certificate is required
Error message
At least one certificate is required
What it means
In 'manual' SNI mode the operator must list TLS certificates (cert+key file pairs) in configuration. If SNI is enabled, mod=manual, and the certificates list is empty or absent, the server cannot establish any SNI mapping and startup fails.
Solutions
- Add at least one certificate entry under shenyu.server.netty.sni.certificates with valid crt/key file paths
- Verify the YAML structure puts certificates under sni.certificates with correct field names
- Check that referenced cert/key files exist and are readable (a later step loads them)
Example fix
# before
shenyu:
server:
netty:
sni:
enabled: true
mod: manual
# after
shenyu:
server:
netty:
sni:
enabled: true
mod: manual
certificates:
- crt: /etc/shenyu/tls/server.crt
key: /etc/shenyu/tls/server.key Defensive patterns
Strategy: validation
Validate before calling
if (sni.isEnabled() && "manual".equals(sni.getMod())
&& (sni.getCertificates() == null || sni.getCertificates().isEmpty())) {
throw new IllegalArgumentException("sni.certificates must list at least one crt/key pair in manual mode");
} Try / catch
try {
SpringApplication.run(GatewayApplication.class, args);
} catch (Exception e) {
if (rootCauseOf(e, ShenyuException.class).map(x -> x.getMessage().contains("certificate is required")).orElse(false)) {
log.error("Add sni.certificates entries or switch sni.mod to k8s");
} else throw e;
} Prevention
- Validate the full SNI block in config CI before deploy
- Provision certificates before enabling SNI
- Bind the certificates list to a typed config class to catch YAML indentation errors early
When it happens
Trigger: shenyu.server.netty.sni.enabled=true with shenyu.server.netty.sni.mod=manual but shenyu.server.netty.sni.certificates is empty, missing, or only contains entries that failed to deserialize into SslCrtAndKeyFile.
Common situations: YAML indentation mistake placing certificates under the wrong key; enabling SNI before provisioning cert files; certificate entries typed with wrong property names so the list binds empty.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Cannot read the sni mod
- Can not find shenyuSniAsyncMapping bean
- The sslCrtAndKeys can not be null
- Could not load KeyStore for type and provider
- Can not read cert and key from default secret
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/738c8688833ab6de.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/netty/ShenyuNettyWebServerConfiguration.java:105
@ConditionalOnProperty(value = "shenyu.netty.http.web-server-factory-enabled", havingValue = "true", matchIfMissing = true)
public NettyReactiveWebServerFactory nettyReactiveWebServerFactory(final ObjectProvider<NettyHttpProperties> properties,
final ObjectProvider<ShenyuSniAsyncMapping> shenyuSniAsyncMappingProvider,
final ObjectProvider<TcpSslContextSpec> tcpSslContextSpecs) {
NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory();
NettyHttpProperties nettyHttpProperties = Optional.ofNullable(properties.getIfAvailable()).orElse(new NettyHttpProperties());
webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer(nettyHttpProperties, httpServer -> {
HttpServer server = httpServer;
// Configure sni certificates
NettyHttpProperties.SniProperties sniProperties = nettyHttpProperties.getSni();
if (sniProperties.getEnabled()) {
ShenyuSniAsyncMapping shenyuSniAsyncMapping = shenyuSniAsyncMappingProvider.getIfAvailable();
if (Objects.isNull(shenyuSniAsyncMapping)) {
throw new ShenyuException("Can not find shenyuSniAsyncMapping bean");
}
if ("manual".equals(sniProperties.getMod())) {
List<SslCrtAndKeyFile> sslCrtAndKeyFiles = sniProperties.getCertificates();
if (CollectionUtils.isEmpty(sslCrtAndKeyFiles)) {
throw new ShenyuException("At least one certificate is required");
}
// Use the first certificate as the default certificate (this default certificate will not actually be used)
List<SslCrtAndKeyFile> certificates = sslCrtAndKeyFiles;
for (SslCrtAndKeyFile certificate : certificates) {
try {
shenyuSniAsyncMapping.addSslCertificate(certificate);
} catch (IOException e) {
LOG.error("add certificate error", e);
}
}
SslCrtAndKeyFile defaultCert = certificates.get(0);
TcpSslContextSpec defaultSpec = TcpSslContextSpec.forServer(new File(defaultCert.getKeyCertChainFile()),
new File(defaultCert.getKeyFile()));
server = server.secure(spec -> spec.sslContext(defaultSpec)
.setSniAsyncMappings(shenyuSniAsyncMapping), false);View on GitHub (pinned to 567142e072)