apache/pulsar · error · RuntimeException
No additional servlet is found for name `${servletName}`. Av
Error message
No additional servlet is found for name `${servletName}`. Available additional servlet are : ${definitions} What it means
AdditionalServlets.load builds the servlet map from the configured additional servlet names; when a configured name has no matching entry in the discovered servlet definitions metadata (from the NAR packages), it throws this RuntimeException. It means a name in the broker's additionalServlets configuration does not correspond to any deployed servlet plugin.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/web/plugin/servlet/AdditionalServlets.java:95
if (additionalServletDirectory == null || additionalServlets == null) {
return null;
}
String[] additionalServletsList = additionalServlets.split(",");
if (additionalServletsList.length == 0) {
return null;
}
AdditionalServletDefinitions definitions =
AdditionalServletUtils.searchForServlets(additionalServletDirectory
, narExtractionDirectory);
ImmutableMap.Builder<String, AdditionalServletWithClassLoader> builder = ImmutableMap.builder();
for (String servletName : additionalServletsList) {
AdditionalServletMetadata definition = definitions.servlets().get(servletName);
if (null == definition) {
throw new RuntimeException("No additional servlet is found for name `" + servletName
+ "`. Available additional servlet are : " + definitions.servlets());
}
AdditionalServletWithClassLoader servletWithClassLoader;
try {
servletWithClassLoader = AdditionalServletUtils.load(definition, narExtractionDirectory);
if (servletWithClassLoader != null) {
builder.put(servletName, servletWithClassLoader);
}
log.info().attr("servlet", servletName).log("Successfully loaded additional servlet");
} catch (IOException e) {
log.error().attr("servlet", servletName).exception(e).log("Failed to load the additional servlet");
throw new RuntimeException("Failed to load the additional servlet for name `" + servletName + "`");
}
}
Map<String, AdditionalServletWithClassLoader> servlets = builder.build();
if (!servlets.isEmpty()) {View on GitHub (pinned to 820761864e)
Solutions
- Compare the configured name against the names listed in the error message (Available additional servlet are: ...) and fix the typo
- Verify the servlet NAR is present in the configured plugins directory and was extracted successfully
- Check the servlet's metadata inside the NAR declares the name you used in configuration
- Remove the stale name from additionalServlets if the plugin is no longer needed
Example fix
// before (broker.conf) additionalServlets=my-servelt // after additionalServlets=my-servlet
Defensive patterns
Strategy: validation
Validate before calling
String requested = "my-servlet";
if (!definitions.servlets().containsKey(requested)) {
throw new IllegalArgumentException("Servlet '" + requested + "' not deployed; available: "
+ definitions.servlets().keySet());
} Try / catch
try {
servlets = AdditionalServlets.load(brokerConfig, narDir);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("No additional servlet is found")) {
log.error("Configured additionalServlets name not found — check name and NAR deployment", e);
}
throw e;
} Prevention
- Copy servlet names exactly from the NAR's metadata
- Confirm the NAR is in the plugins directory before referencing it in config
- Remove names of plugins you have undeployed
When it happens
Trigger: Broker config additionalServlets contains a servlet name that is not present in definitions.servlets() — i.e., no loaded NAR exposes a servlet with that exact name.
Common situations: Typo in the additionalServlets config value; the servlet NAR was never copied to the plugins directory; the NAR's metadata declares a different servlet name than the one configured; the NAR failed to be discovered (wrong directory or extraction failure).
Related errors
- ${key} already exists in the dynamicConfigurationMap
- Additional servlets `${name}` does NOT provide an additional
- Additional servlet instance of type ${className} doesn't imp
- The '${offloaderName}' offloader does not provide an offload
- webServicePort/webServicePortTls or http/https bindAddresses
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/851b15ac45338d1d.
Report an issue: GitHub.