{"record":{"id":"8d8221b768e457f8","repo":"apache/beam","slug":"rate-limit-service-returned-unknown-code","errorCode":null,"errorMessage":"Rate Limit Service returned unknown code: ","messagePattern":"Rate Limit Service returned unknown code: ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/ratelimiter/EnvoyRateLimiterFactory.java","lineNumber":234,"sourceCode":"        }\n\n        long jitter =\n            (long)\n                (java.util.concurrent.ThreadLocalRandom.current().nextDouble()\n                    * (0.1 * sleepMillis));\n        sleepMillis += jitter;\n\n        LOG.warn(\"Throttled by RLS, sleeping for {} ms\", sleepMillis);\n        if (sleeper != null) {\n          requestsThrottled.inc();\n          if (throttlingSignaler != null) {\n            throttlingSignaler.signalThrottling(sleepMillis);\n          }\n          sleeper.sleep(sleepMillis);\n        }\n        attempt++;\n      } else {\n        throw new IOException(\n            \"Rate Limit Service returned unknown code: \" + response.getOverallCode());\n      }\n    }\n  }\n}\n","sourceCodeStart":216,"sourceCodeEnd":240,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/ratelimiter/EnvoyRateLimiterFactory.java#L216-L240","documentation":"After receiving a RateLimitResponse, fetchTokens() handles the documented codes OK (allow) and OVER_LIMIT (throttle/sleep/retry). If response.getOverallCode() is anything else — e.g. an UNKNOWN or unmapped enum value — it throws IOException(\"Rate Limit Service returned unknown code: \" + code), since the caller cannot know whether the request was permitted.","triggerScenarios":"The Envoy rate-limit service returns a RateLimitResponse whose overall code is neither OK nor OVER_LIMIT, such as UNKNOWN from a malfunctioning server or a code from a newer service proto not understood by this connector version.","commonSituations":"Version skew between the rate-limit service and the connector's generated protobuf (new enum values), a misbehaving or proxied rate-limit implementation, or corrupted responses.","solutions":["Check the reported code in the message and the rate-limit service's health/logs to see why it returns UNKNOWN.","Align protobuf/service versions — regenerate the rate-limit proto bindings or upgrade/downgrade the service so codes match.","Decide on a fail-open/fail-closed policy: catch this IOException and either allow or deny requests when the code is unknown."],"exampleFix":"// before\n// response.getOverallCode() == UNKNOWN -> throws IOException\n// after\ntry {\n  allowed = factory.allow(context, 1);\n} catch (IOException e) {\n  allowed = true; // fail-open policy for unknown rate-limit codes\n}","handlingStrategy":"try-catch","validationCode":"// pin protobuf/service versions so enum values are known on both sides\n// in build.gradle: implementation 'io.envoyproxy.envoy:... (<same version as rate-limit service>')","typeGuard":null,"tryCatchPattern":"try {\n  allowed = factory.allow(ctx, permits);\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Rate Limit Service returned unknown code\")) {\n    allowed = true; // explicit fail-open (or false for fail-closed) policy\n  } else {\n    throw e;\n  }\n}","preventionTips":["Keep the rate-limit service and connector proto versions aligned.","Check rate-limit service logs when UNKNOWN codes appear.","Decide and document a fail-open vs fail-closed policy for unknown codes."],"tags":["grpc","rate-limiting","envoy","protocol"],"backgroundTag":"unexpected-api-response-shape","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"}