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

  1. Look at the preceding 'Failed to load the additional servlet' error log entry for the full IOException stack trace
  2. Verify the NAR file is a valid, uncorrupted zip with correct permissions
  3. Check the narExtractionDirectory exists, is writable, and has free disk space
  4. 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

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


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/6218b2adb119fced. Report an issue: GitHub.