{"record":{"id":"4c7a85c652732438","repo":"apache/hadoop","slug":"error-creating-plugin","errorCode":null,"errorMessage":"Error creating plugin: {}","messagePattern":"Error creating plugin: (.+?)","errorType":"exception","errorClass":"MetricsConfigException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/impl/MetricsConfig.java","lineNumber":210,"sourceCode":"                                     : PREFIX_DEFAULT + key);\n    }\n    LOG.debug(\"Returning '{}' for key: {}\", value, key);\n    return value;\n  }\n\n  <T extends MetricsPlugin> T getPlugin(String name) {\n    String clsName = getClassName(name);\n    if (clsName == null) {\n      return null;\n    }\n    try {\n      Class<?> cls = Class.forName(clsName, true, getPluginLoader());\n      @SuppressWarnings(\"unchecked\")\n      T plugin = (T) cls.newInstance();\n      plugin.init(name.isEmpty() ? this : subset(name));\n      return plugin;\n    } catch (Exception e) {\n      throw new MetricsConfigException(\"Error creating plugin: \"+ clsName, e);\n    }\n  }\n\n  String getClassName(String prefix) {\n    String classKey = prefix.isEmpty() ? \"class\" : prefix.concat(\".class\");\n    String clsName = getString(classKey);\n    LOG.debug(\"Class name for prefix {} is {}\", prefix, clsName);\n    if (clsName == null || clsName.isEmpty()) {\n      return null;\n    }\n    return clsName;\n  }\n\n  ClassLoader getPluginLoader() {\n    if (pluginLoader != null) {\n      return pluginLoader;\n    }\n    final ClassLoader defaultLoader = getClass().getClassLoader();","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/impl/MetricsConfig.java#L192-L228","documentation":"MetricsConfig.getPlugin reflectively instantiates every metrics2 source/sink/filter named by a *.class property in hadoop-metrics2.properties: Class.forName with the plugin classloader, newInstance(), then plugin.init(subsetConfig). Any failure — class not found, no accessible no-arg constructor, ClassCastException to MetricsPlugin, or an exception thrown inside init() — is wrapped in MetricsConfigException('Error creating plugin: <className>') with the original cause attached. It surfaces during MetricsSystem init, typically at daemon startup or first metrics use.","triggerScenarios":"*.sink.custom.class=com.example.MySink where the jar is absent from the daemon classpath; class lacks a public no-arg constructor; class does not implement MetricsSink/MetricsSource; plugin.init() throws because its own config subset is incomplete (e.g., FileSink without a filename).","commonSituations":"Deploying custom metrics sinks (Graphite/Kafka/Prometheus writers) and forgetting the jar or shading it wrongly; typo in the class property; version upgrades renaming plugin classes; sink-specific properties missing after config migration.","solutions":["Read the nested cause first (getCause()) — it distinguishes ClassNotFoundException vs InstantiationException vs init() failure and points at the real fix.","Verify the class name spelling and that the jar is on the daemon's classpath (put it in HADOOP_COMMON_LIB_NATIVE or the service lib dir) with a public no-arg constructor implementing the right MetricsPlugin interface.","Fix the plugin's own config subset (its sink/source properties) if the cause is an init() exception.","As a stopgap, comment out the offending *.class property to restore metrics startup, then redeploy the fixed plugin."],"exampleFix":"# before\n*.sink.graph.class=com.example.GraphiteSink   # jar missing on nodes\n\n# after\ncp graphite-metrics-sink.jar $HADOOP_HOME/share/hadoop/common/lib/\n# or, to restore startup immediately:\n# *.sink.graph.class=org.apache.hadoop.metrics2.sink.FileSink\n# *.sink.graph.filename=/tmp/metrics.out","handlingStrategy":"try-catch","validationCode":"// Smoke-test a configured plugin class before trusting it in production\nString clsName = metricsConf.getString(\"sink.custom.class\");\nClass<?> c = Class.forName(clsName, true, pluginClassLoader);\nif (!org.apache.hadoop.metrics2.MetricsSink.class.isAssignableFrom(c)\n    && !org.apache.hadoop.metrics2.MetricsSource.class.isAssignableFrom(c)) {\n  throw new IllegalArgumentException(clsName + \" implements neither MetricsSink nor MetricsSource\");\n}\nc.getConstructor(); // fails fast without a public no-arg ctor","typeGuard":null,"tryCatchPattern":"try {\n  MetricsSource src = conf.getPlugin(\"source.custom\");\n} catch (MetricsConfigException mce) {\n  Throwable root = mce.getCause() != null ? mce.getCause() : mce;\n  LOG.error(\"metrics2 plugin failed to load: {} (cause: {})\",\n      mce.getMessage(), root.toString());\n  // decide: fall back to a stock sink or abort startup with a clear message\n}","preventionTips":["Always inspect getCause() of MetricsConfigException — it distinguishes missing jar, bad constructor, and init-config errors.","Deploy custom metrics plugin jars to every daemon and verify with 'hadoop classpath' before enabling the .class property.","Require a public no-arg constructor and the correct MetricsPlugin interface in plugin code reviews.","Keep a known-good fallback sink config (e.g., FileSink) commented in hadoop-metrics2.properties for quick recovery."],"tags":["hadoop","metrics2","configuration","plugin","reflection","classpath"],"backgroundTag":"plugin-load-failure","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}