apache/pulsar · error · RuntimeException
Failed to load the additional servlet for name `${servletNam
Error message
Failed to load the additional servlet for name `${servletName}` What it means
When AdditionalServletUtils.load throws an IOException while loading a configured servlet (NAR extraction, classloading, instantiation), this RuntimeException is thrown with the servlet name in the message. The original IOException is logged at error level before rethrow, so the root cause is in the log, not in the exception message.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/web/plugin/servlet/AdditionalServlets.java:108
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()) {
return new AdditionalServlets(servlets);
}
return null;
}
@Override
public void close() {
servlets.values().forEach(AdditionalServletWithClassLoader::close);
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Look at the preceding 'Failed to load the additional servlet' error log entry for the full IOException stack trace
- Verify the NAR file is a valid, uncorrupted zip with correct permissions
- Check the narExtractionDirectory exists, is writable, and has free disk space
- Rebuild the plugin NAR if its classes fail to initialize on your Pulsar version
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check the NAR and extraction dir
if (!Files.isReadable(Path.of(narPath)) || !Files.isWritable(Path.of(narExtractionDirectory))) {
throw new IllegalStateException("NAR unreadable or extraction directory not writable");
} Try / catch
try {
servlets = AdditionalServlets.load(brokerConfig, narDir);
} catch (RuntimeException e) {
// root IOException was logged by the library; surface it with context
throw new IllegalStateException("Additional servlet failed to load; see prior error log for the IOException", e);
} Prevention
- Check disk space and permissions on the NAR extraction directory
- Validate NAR files after transfer (checksums)
- Match plugin versions to the broker version
When it happens
Trigger: IOException propagated from AdditionalServletUtils.load during the servlet NAR load — failed NAR file read, extraction directory problems, or class instantiation failures wrapped as IOException (see rethrowIOException).
Common situations: Corrupted or incomplete NAR upload; no read permission on the NAR file or no write permission on the NAR extraction directory; disk full during extraction; plugin class throws during initialization.
Related errors
- Additional servlets `${name}` does NOT provide an additional
- Class ${className} does not implement additional servlet int
- cause.getMessage()
- Unsupported additional servlet type ${servletType}
- Additional servlet instance of type ${className} doesn't imp
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/6218b2adb119fced.
Report an issue: GitHub.