pinpoint-apm/pinpoint · error · RuntimeException
${pluginConfig.getPluginJarURLExternalForm()} read fail.${ex
Error message
${pluginConfig.getPluginJarURLExternalForm()} read fail.${ex.getMessage()} What it means
PlainClassLoaderHandler.readJar() reads all .class entries from the plugin jar via JarReader.read() to build class metadata. If any I/O error occurs while opening/reading the plugin jar, it rethrows it as a RuntimeException prefixed with the plugin jar's URL and the IOException message. This means the agent could not enumerate the plugin jar's class files, so plugin classes cannot be defined into the target classloader.
Source
Thrown at agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java:230
List<FileBinary> fileBinaryList = readJar();
Map<String, SimpleClassMetadata> classEntryMap = parse(fileBinaryList);
for (Map.Entry<String, SimpleClassMetadata> entry : classEntryMap.entrySet()) {
final SimpleClassMetadata classMetadata = entry.getValue();
if (meetsRequirement(classMetadata.getClassName(), classLoader)) {
ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker();
classLoadingChecker.isFirstLoad(classMetadata.getClassName());
define0(classLoader, attachment, classMetadata, classEntryMap, classLoadingChecker);
}
}
}
private List<FileBinary> readJar() {
try {
return pluginJarReader.read(ExtensionFilter.CLASS_FILTER);
} catch (IOException ex) {
throw new RuntimeException(pluginConfig.getPluginJarURLExternalForm() + " read fail." + ex.getMessage(), ex);
}
}
private Map<String, SimpleClassMetadata> parse(List<FileBinary> fileBinaryList) {
Map<String, SimpleClassMetadata> parseMap = new HashMap<>();
for (FileBinary fileBinary : fileBinaryList) {
SimpleClassMetadata classNode = parseClass(fileBinary);
parseMap.put(classNode.getClassName(), classNode);
}
return parseMap;
}
private SimpleClassMetadata parseClass(FileBinary fileBinary) {
byte[] fileBinaryArray = fileBinary.getFileBinary();
return SimpleClassMetadataReader.readSimpleClassMetadata(fileBinaryArray);
}
private void define0(final ClassLoader classLoader, ClassLoaderAttachment attachment, SimpleClassMetadata currentClass, Map<String, SimpleClassMetadata> classMetaMap, ClassLoadingChecker classLoadingChecker) {View on GitHub (pinned to 744c3d3075)
Solutions
- Verify the plugin jar at the URL printed in the message exists and is a valid jar: run `unzip -t <pluginJarPath>`; re-download/rebuild the plugin if the test fails.
- Check file read permissions for the user running the pinpoint agent on the plugin jar and its directory (chmod/chown as needed).
- Confirm profiler.plugin.dir (or equivalent plugin config) points to the real plugin directory, not a staging/temp path that has been cleaned up.
- Restart the agent after replacing/upgrading plugin jars so PluginConfig references a fresh, stable File instead of a deleted one.
- Inspect the wrapped IOException cause for the underlying reason (file not found vs. missing zip END_HEADER) and fix accordingly.
Example fix
# before (invalid/corrupted jar) ls $AGENT_HOME/plugin tomcat-instrumentation-0.0.1-SNAPSHOT.jar # 12 bytes, partial download # after mv tomcat-instrumentation-0.0.1-SNAPSHOT.jar /tmp/broken.jar mv ~/.m2/.../tomcat-instrumentation-0.0.1-SNAPSHOT.jar $AGENT_HOME/plugin/ unzip -t $AGENT_HOME/plugin/tomcat-instrumentation-0.0.1-SNAPSHOT.jar # 'No errors detected'
Defensive patterns
Strategy: validation
Validate before calling
// before starting the agent, validate every plugin jar
File pluginJar = new File(pluginDir, "my-plugin.jar");
if (!pluginJar.isFile() || pluginJar.length() == 0) throw new IllegalStateException("missing plugin jar");
try (JarFile jf = new JarFile(pluginJar)) {
if (jf.getEntry("com/myplugin/MyPlugin.class") == null) throw new IllegalStateException("plugin jar incomplete");
} catch (IOException e) { throw new IllegalStateException("corrupted/unreadable plugin jar: " + pluginJar, e); } Type guard
static boolean isReadableJar(File f) {
try (JarFile jf = new JarFile(f)) { return f.canRead(); }
catch (IOException e) { return false; }
} Try / catch
try {
injector.injectClass(cl, className);
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException && e.getMessage().contains("read fail.")) {
logger.error("plugin jar unreadable: {}", pluginJarPath, e.getCause());
// fail fast or degrade without this plugin
} else throw e;
} Prevention
- Validate plugin jars with `unzip -t` in the deployment pipeline before shipping to the agent host.
- Never replace plugin jars in place while the agent runs; restart after upgrades.
- Pin plugin jar versions and verify checksums after download.
- Ensure the user running the JVM has read access to $AGENT_HOME/plugin/.
When it happens
Trigger: Plugin class injection triggers defineJarClass() -> readJar() when a class from the plugin package must be defined into an application classloader; JarReader.read(ExtensionFilter.CLASS_FILTER) throws IOException because the jar is missing, corrupted, unreadable (permissions), deleted while the agent runs, or not a valid zip/jar (e.g. an HTML error page saved as a jar, or a truncated download).
Common situations: Wrong pinpoint plugin dir configured so the 'jar' is a placeholder or partial download; corrupted plugin jar after a failed in-place upgrade while the agent was running; file permissions changed by deployment tooling; disk/network mount issues making the jar unreadable; broken plugin packaging step.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- ${interfaceName} not found
- Failed to load plugin class ${className} with classLoader ${
- %s load fail Caused by:%s
- can read
- create fail Caused by:
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/b1fb05df70392bc6.
Report an issue: GitHub.