apache/beam · error · IOException
Rate Limit Service returned unknown code:
Error message
Rate Limit Service returned unknown code:
What it means
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.
Source
Thrown at sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/ratelimiter/EnvoyRateLimiterFactory.java:234
}
long jitter =
(long)
(java.util.concurrent.ThreadLocalRandom.current().nextDouble()
* (0.1 * sleepMillis));
sleepMillis += jitter;
LOG.warn("Throttled by RLS, sleeping for {} ms", sleepMillis);
if (sleeper != null) {
requestsThrottled.inc();
if (throttlingSignaler != null) {
throttlingSignaler.signalThrottling(sleepMillis);
}
sleeper.sleep(sleepMillis);
}
attempt++;
} else {
throw new IOException(
"Rate Limit Service returned unknown code: " + response.getOverallCode());
}
}
}
}
View on GitHub (pinned to 12126d8942)
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.
Example fix
// before
// response.getOverallCode() == UNKNOWN -> throws IOException
// after
try {
allowed = factory.allow(context, 1);
} catch (IOException e) {
allowed = true; // fail-open policy for unknown rate-limit codes
} Defensive patterns
Strategy: try-catch
Validate before calling
// pin protobuf/service versions so enum values are known on both sides // in build.gradle: implementation 'io.envoyproxy.envoy:... (<same version as rate-limit service>')
Try / catch
try {
allowed = factory.allow(ctx, permits);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Rate Limit Service returned unknown code")) {
allowed = true; // explicit fail-open (or false for fail-closed) policy
} else {
throw e;
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- EnvoyRateLimiterFactory requires EnvoyRateLimiterContext
- EnvoyRateLimiterFactory requires EnvoyRateLimiterContext, go
- RateLimitServiceStub is null
- Failed to call Rate Limit Service
- Failed to get response from Rate Limit Service
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/8d8221b768e457f8.
Report an issue: GitHub.