{"record":{"id":"447224070495a4a4","repo":"apache/pulsar","slug":"cause-getmessage","errorCode":null,"errorMessage":"cause.getMessage()","messagePattern":"cause\\.getMessage\\(\\)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/web/plugin/servlet/AdditionalServletUtils.java","lineNumber":204,"sourceCode":"                }\n            }\n            default -> throw new IllegalArgumentException(\"Unsupported additional servlet type \" + servletType);\n        }\n        throw new IllegalArgumentException(\"Additional servlet instance of type \"\n                + (servletInstance == null ? \"null\" : servletInstance.getClass().getName())\n                + \" doesn't implement the servlet interface required by the declared servlet type \" + servletType);\n    }\n\n    private void rethrowIOException(Throwable cause)\n            throws IOException {\n        if (cause instanceof IOException) {\n            throw (IOException) cause;\n        } else if (cause instanceof RuntimeException) {\n            throw (RuntimeException) cause;\n        } else if (cause instanceof Error) {\n            throw (Error) cause;\n        } else {\n            throw new IOException(cause.getMessage(), cause);\n        }\n    }\n}\n","sourceCodeStart":186,"sourceCodeEnd":208,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/web/plugin/servlet/AdditionalServletUtils.java#L186-L208","documentation":"rethrowIOException normalizes a Throwable thrown while loading an additional servlet: IOException, RuntimeException, and Error are rethrown as-is; anything else is wrapped in a new IOException whose message is cause.getMessage(). Developers see this as an IOException during servlet (NAR) loading whose text is the underlying cause's message.","triggerScenarios":"AdditionalServletUtils.load encounters a checked, non-IOException, non-RuntimeException, non-Error Throwable during servlet class loading/instantiation (e.g. a custom checked exception from plugin static initializers or class definition failures surfaced as a checked type).","commonSituations":"Corrupt or incompatible NAR files whose classloading throws unusual checked exceptions; plugin code throwing custom checked exceptions during initialization; unusual filesystem errors surfaced through non-standard exception types.","solutions":["Inspect the IOException's message and its cause stack trace to find the underlying loading failure","Rebuild/redeploy the servlet NAR — the cause is almost always in the plugin package","Enable debug logging for the additional servlet loading path to capture the original throwable"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Ensure the NAR file exists and is readable before load\njava.io.File nar = new java.io.File(narPath);\nif (!nar.isFile() || !nar.canRead()) throw new java.io.FileNotFoundException(narPath);","typeGuard":null,"tryCatchPattern":"try {\n    servlet = AdditionalServletUtils.load(definition, narDir);\n} catch (IOException e) {\n    // message is cause.getMessage(); inspect cause chain for the real failure\n    Throwable root = e; while (root.getCause() != null) root = root.getCause();\n    log.error(\"Servlet load failed, root cause: {}\", root.toString(), e);\n}","preventionTips":["Always log the full cause chain — the IOException message is only the root message","Verify NAR integrity (unzip -t) before deploying","Keep plugin initialization code free of exotic checked exceptions"],"tags":["servlet","plugin","io","exception-wrapping"],"backgroundTag":"exception-wrapping","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}