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

  1. Check the reported code in the message and the rate-limit service's health/logs to see why it returns UNKNOWN.
  2. Align protobuf/service versions — regenerate the rate-limit proto bindings or upgrade/downgrade the service so codes match.
  3. 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

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


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/8d8221b768e457f8. Report an issue: GitHub.