{"record":{"id":"4485368943b1c839","repo":"bazelbuild/bazel","slug":"could-not-create-custom-sharding-strategy-class","errorCode":null,"errorMessage":"Could not create custom sharding strategy class ${strategy}","messagePattern":"Could not create custom sharding strategy class (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/java_tools/junitrunner/java/com/google/testing/junit/runner/sharding/ShardingFilters.java","lineNumber":104,"sourceCode":"        shardingEnvironment.getTotalShards());\n  }\n\n  private ShardingFilterFactory getShardingFilterFactory() {\n    String strategy = shardingEnvironment.getTestShardingStrategy();\n    if (strategy == null) {\n      return defaultShardingStrategy;\n    }\n    ShardingFilterFactory shardingFilterFactory;\n    try {\n      shardingFilterFactory = ShardingStrategy.valueOf(strategy.toUpperCase(Locale.ENGLISH));\n    } catch (IllegalArgumentException e) {\n      try {\n        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n        Class<? extends ShardingFilterFactory> strategyClass =\n            classLoader.loadClass(strategy).asSubclass(ShardingFilterFactory.class);\n        shardingFilterFactory = strategyClass.getConstructor().newInstance();\n      } catch (ReflectiveOperationException | IllegalArgumentException e2) {\n        throw new RuntimeException(\n            \"Could not create custom sharding strategy class \" + strategy, e2);\n      }\n    }\n    return shardingFilterFactory;\n  }\n}\n","sourceCodeStart":86,"sourceCodeEnd":111,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/java_tools/junitrunner/java/com/google/testing/junit/runner/sharding/ShardingFilters.java#L86-L111","documentation":"Thrown by ShardingFilters.getShardingFilterFactory when the system property test.sharding.strategy is neither a value of the ShardingStrategy enum (compared case-insensitively) nor a loadable class name. The code first tries valueOf(), then falls back to reflection: load the class via the context classloader, narrow it to ShardingFilterFactory, and instantiate via a no-arg constructor. Any ReflectiveOperationException in that fallback is wrapped in this RuntimeException.","triggerScenarios":"Setting -Dtest.sharding.strategy=custom.factory (or a typo like \"defualt\") where the class is missing from the test classpath, does not implement ShardingFilterFactory, is not public, lacks a public no-arg constructor, or its constructor throws.","commonSituations":"Teams experimenting with custom sharding plug-ins who forget to add the factory jar to the test's deps; typos in the strategy property; refactoring that renamed or removed the factory class without updating the flag.","solutions":["Use a built-in enum value of ShardingStrategy (e.g. DEFAULT) spelled exactly, case-insensitively.","For a custom factory: ensure the class is on the test runtime classpath (deps of the java_test / runner config).","Verify the class is public, implements com.google.testing.junit.runner.sharding.ShardingFilterFactory, and has a public no-arg constructor that does not throw.","Read the suppressed cause (e2) from the stack trace: ClassNotFoundException vs ClassCastException vs InvocationTargetException tells you which link broke."],"exampleFix":"// before\npublic final class MySharding implements ShardingFilterFactory {\n  MySharding(ShardIndex idx) {...}  // package-private, no no-arg ctor\n}\n// after\npublic final class MySharding implements ShardingFilterFactory {\n  public MySharding() {}  // public no-arg constructor required\n}","handlingStrategy":"try-catch","validationCode":"// verify a custom strategy before setting the property\nString strategy = \"com.mycorp.MyShardingFactory\";\nif (!ShardingFilters.ShardingStrategy.VALID_NAMES.contains(strategy.toUpperCase(Locale.ROOT))) {\n  Class<?> c = Class.forName(strategy); // ClassNotFoundException surfaces early\n  if (!ShardingFilterFactory.class.isAssignableFrom(c)\n      || c.getConstructor() == null) {\n    throw new IllegalArgumentException(\"Bad sharding strategy: \" + strategy);\n  }\n}","typeGuard":"static boolean isValidShardingStrategy(String s) {\n  try {\n    ShardingFilters.ShardingStrategy.valueOf(s.toUpperCase(Locale.ENGLISH));\n    return true;\n  } catch (IllegalArgumentException e) {\n    try {\n      return ShardingFilterFactory.class\n          .isAssignableFrom(Thread.currentThread().getContextClassLoader().loadClass(s));\n    } catch (ClassNotFoundException cnf) { return false; }\n  }\n}","tryCatchPattern":"try {\n  ShardingFilters.createShardingFilterFactory(...);\n} catch (RuntimeException e) {\n  Throwable cause = e.getCause(); // ReflectiveOperationException tells which step failed\n  log.config(\"Invalid test.sharding.strategy, falling back to DEFAULT: \" + cause);\n}","preventionTips":["Keep custom ShardingFilterFactory implementations public with a public no-arg constructor.","Add the factory jar as a runtime dep of every test that uses the strategy.","Pin the strategy property in a checked-in bazelrc so typos surface at config review."],"tags":["bazel","sharding","reflection","classpath","configuration"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}