Skip to content

RateLimiterFilter returns HTTP 429 with empty body which can result in unexpected parsing error when clients expect JSON #4402

@travis-bowen

Description

@travis-bowen

Describe the bug

RateLimiterFilter returns HTTP 429 with an empty body and no Content-Type header:

ctx.abortWith(Response.status(Response.Status.TOO_MANY_REQUESTS).build());

Iceberg REST clients using standard Iceberg SDKs (pyiceberg, Spark, and any third-party caller) cannot parse this response. Iceberg's ErrorHandlers has no case 429:, so the catch-all path produces an opaque RESTException("Unable to process: ") with no useful context for the caller.

With a fix to return an error message, Iceberg SDK will still throw a generic REST exception but will at least have useful information.
It seems like common catalog implementations such AWS Glue, Nessie, and Unity provide a body in the response for 429s.

I'll put up a PR shortly for a proposed fix.

To Reproduce

Update the RateLimiter to be small enough to hit the rate limit output

Actual Behavior

Returns an empty response resulting in no useful information in Iceberg SDK Error Handling Parsing.

Expected Behavior

A 429 response should include an Iceberg-compatible ErrorResponse JSON body, consistent with the shape IcebergExceptionMapper already produces for other error codes:

  {                                                                                                                                                                                   
    "error": {                                                                                                                                                                        
      "code": 429,                                                                                                                                                                    
      "type": "RateLimitExceededException",                                                                                                                                           
      "message": "Rate exceeded"                                                                                                                                                      
    }                                                                                                                                                                                 
  }     

Additional context

No response

System information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions