{"record":{"id":"1d19b542021a4701","repo":"apache/beam","slug":"cannot-determine-context-class","errorCode":null,"errorMessage":"Cannot determine context class","messagePattern":"Cannot determine context class","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/cdap/src/main/java/org/apache/beam/sdk/io/cdap/Plugin.java","lineNumber":231,"sourceCode":"    Class<?> contextClass;\n    List<Method> methods = new ArrayList<>(Arrays.asList(cdapPluginClass.getDeclaredMethods()));\n    Class<?> cdapPluginSuperclass = cdapPluginClass.getSuperclass();\n    if (cdapPluginSuperclass != null) {\n      methods.addAll(Arrays.asList(cdapPluginSuperclass.getDeclaredMethods()));\n    }\n    for (Method method : methods) {\n      if (method.getName().equals(PREPARE_RUN_METHOD_NAME)) {\n        contextClass = method.getParameterTypes()[0];\n        if (contextClass.equals(BatchSourceContext.class)) {\n          return new BatchSourceContextImpl();\n        } else if (contextClass.equals(BatchSinkContext.class)) {\n          return new BatchSinkContextImpl();\n        }\n      } else if (method.getName().equals(GET_STREAM_METHOD_NAME)) {\n        return new StreamingSourceContextImpl();\n      }\n    }\n    throw new IllegalStateException(\"Cannot determine context class\");\n  }\n\n  /** Gets value of a plugin type. */\n  public Boolean isUnbounded() {\n    Boolean isUnbounded = null;\n\n    for (Annotation annotation : getPluginClass().getDeclaredAnnotations()) {\n      if (annotation.annotationType().equals(io.cdap.cdap.api.annotation.Plugin.class)) {\n        String pluginType = ((io.cdap.cdap.api.annotation.Plugin) annotation).type();\n        isUnbounded = pluginType != null && pluginType.startsWith(\"streaming\");\n      }\n    }\n    if (isUnbounded == null) {\n      throw new IllegalArgumentException(\"CDAP plugin class must have Plugin annotation!\");\n    }\n    return isUnbounded;\n  }\n","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/cdap/src/main/java/org/apache/beam/sdk/io/cdap/Plugin.java#L213-L249","documentation":"Plugin.initContext scans the CDAP plugin class's declared methods to decide which context implementation (batch source, batch sink, or streaming source) to instantiate, matching by method name (e.g., GET_STREAM_METHOD_NAME). When no method matches any known pattern, the loop completes without returning and the method throws IllegalStateException, because the plugin type could not be inferred.","triggerScenarios":"Invoking initContext (indirectly via the CDAP connector expand path) on a plugin class whose introspected methods do not include the expected source/sink accessor method names — for example a plugin that overrides method names, or a plugin class whose type was misclassified upstream.","commonSituations":"Using a custom CDAP plugin that deviates from the standard BatchSource/BatchSink method contract; class obfuscation or shading renaming accessor methods; mixing CDAP plugin versions where the expected method names changed.","solutions":["Confirm the plugin class exposes the standard accessor methods the adapter looks for (matching the GET_..._METHOD_NAME constants)","Regenerate/rebuild the plugin from a current CDAP archetype so method naming matches the contract","Check that the plugin was correctly classified as source vs sink before initContext runs","If using obfuscation (ProGuard/minification), keep the plugin accessor method names"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"boolean hasStandardAccessors(Class<?> pluginClass) {\n  for (Method m : pluginClass.getDeclaredMethods()) {\n    String n = m.getName();\n    if (n.contains(\"Source\") || n.contains(\"Sink\")) return true;\n  }\n  return false;\n}","typeGuard":"static boolean isInitContextSafe(Class<?> c) {\n  return java.util.Arrays.stream(c.getDeclaredMethods())\n      .map(Method::getName)\n      .anyMatch(n -> n.contains(\"Source\") || n.contains(\"Sink\"));\n}","tryCatchPattern":"try {\n  return initContext(cdapPluginClass);\n} catch (IllegalStateException e) {\n  LOG.error(\"Plugin {} lacks expected source/sink accessor methods\", cdapPluginClass.getName(), e);\n  throw e;\n}","preventionTips":["Build plugins from the standard CDAP archetypes so accessor method names match the contract","Disable code obfuscation/renaming for CDAP plugin classes","Keep the CDAP plugin API dependency version aligned with the Beam cdap IO module"],"tags":["java","cdap","beam","reflection","context"],"backgroundTag":"internal-invariant-violation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}