{"record":{"id":"a5e617e40182d28d","repo":"apache/beam","slug":"envoyratelimiterfactory-requires-envoyratelimitercontext","errorCode":null,"errorMessage":"EnvoyRateLimiterFactory requires EnvoyRateLimiterContext","messagePattern":"EnvoyRateLimiterFactory requires EnvoyRateLimiterContext","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/ratelimiter/EnvoyRateLimiterFactory.java","lineNumber":108,"sourceCode":"    }\n    synchronized (this) {\n      if (stub == null) {\n        RateLimiterClientCache cache = RateLimiterClientCache.getOrCreate(options.getAddress());\n        this.clientCache = cache;\n        stub = RateLimitServiceGrpc.newBlockingStub(cache.getChannel());\n      }\n    }\n  }\n\n  @VisibleForTesting\n  void setStub(RateLimitServiceGrpc.RateLimitServiceBlockingStub stub) {\n    this.stub = stub;\n  }\n\n  @Override\n  public RateLimiter getLimiter(RateLimiterContext context) {\n    if (!(context instanceof EnvoyRateLimiterContext)) {\n      throw new IllegalArgumentException(\n          \"EnvoyRateLimiterFactory requires EnvoyRateLimiterContext\");\n    }\n    return new EnvoyRateLimiter(this, (EnvoyRateLimiterContext) context);\n  }\n\n  @Override\n  public boolean allow(RateLimiterContext context, int permits)\n      throws IOException, InterruptedException {\n    if (permits == 0) {\n      return true;\n    }\n    if (!(context instanceof EnvoyRateLimiterContext)) {\n      throw new IllegalArgumentException(\n          \"EnvoyRateLimiterFactory requires EnvoyRateLimiterContext, got: \"\n              + context.getClass().getName());\n    }\n    checkArgument(permits >= 0, \"Permits must be non-negative\");\n    EnvoyRateLimiterContext envoyContext = (EnvoyRateLimiterContext) context;","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/ratelimiter/EnvoyRateLimiterFactory.java#L90-L126","documentation":"EnvoyRateLimiterFactory.getLimiter(context) only accepts a RateLimiterContext that is an instance of EnvoyRateLimiterContext; any other context implementation is rejected with IllegalArgumentException. The factory needs Envoy-specific data (like descriptors) that a generic context does not carry.","triggerScenarios":"Passing a RateLimiterContext created by another factory (or a plain/default context implementation) into EnvoyRateLimiterFactory.getLimiter().","commonSituations":"Mixing rate limiter factories and contexts in configuration (e.g. a generic context built for a different backend), or after refactoring/swapping the limiter implementation while reusing old context objects.","solutions":["Construct an EnvoyRateLimiterContext (via its builder) and pass that to getLimiter().","Use the matching factory for the context type you have, or a factory that accepts generic contexts.","Check the context's runtime class (instanceof EnvoyRateLimiterContext) before wiring it into this factory."],"exampleFix":"// before\nRateLimiter limiter = envoyFactory.getLimiter(genericContext); // throws\n// after\nEnvoyRateLimiterContext ctx = EnvoyRateLimiterContext.builder().setDescriptors(descriptors).build();\nRateLimiter limiter = envoyFactory.getLimiter(ctx);","handlingStrategy":"type-guard","validationCode":"if (!(ctx instanceof EnvoyRateLimiterContext)) {\n  throw new IllegalArgumentException(\"build EnvoyRateLimiterContext for EnvoyRateLimiterFactory\");\n}","typeGuard":"static boolean isEnvoyContext(RateLimiterContext ctx) {\n  return ctx instanceof EnvoyRateLimiterContext;\n}","tryCatchPattern":"try {\n  RateLimiter limiter = factory.getLimiter(ctx);\n} catch (IllegalArgumentException e) {\n  ctx = EnvoyRateLimiterContext.builder().setDescriptors(descriptors).build();\n  RateLimiter limiter = factory.getLimiter(ctx);\n}","preventionTips":["Always construct contexts with the factory that will consume them.","Centralize context creation so Envoy factories only ever see EnvoyRateLimiterContext.","Prefer getLimiter(ctx) once at setup over raw allow() calls with shared contexts."],"tags":["rate-limiting","envoy","grpc","type-check"],"backgroundTag":"type-mismatch","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"}