apache / apache/iceberg

REST: Freshness-aware loading breaks when the server writes the ETag header in lowercase

Closed Beginner friendly
#17,978 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
9.2k
Forks
3.5k
Avg merge
2d 11h
Merged PRs (30d)
132

Description

### Apache Iceberg version

1.11.0 (latest release)

### Query engine

None

### Please describe the bug

Freshness-aware table loading silently does nothing when the catalog server writes the `ETag` response header in any spelling other than `ETag`.

`HTTPClient` hands response headers to callers in a map keyed by the name exactly as it came off the wire:

```java
// core/src/main/java/org/apache/iceberg/rest/HTTPClient.java
Map respHeaders = Maps.newHashMap();
for (Header header : response.getHeaders()) {
respHeaders.put(header.getName(), header.getValue());
}
responseHeaders.accept(respHeaders);
```

`RESTSessionCatalog` copies that into another `HashMap` and reads the tag back by its traditional spelling:

```java
// core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
String eTag = responseHeaders.getOrDefault(HttpHeaders.ETAG, null); // "ETag"
if (eTag != null) {
tableCache.put(context.sessionId(), finalIdentifier, tableSupplier, eTag);
}
```

HTTP field names are case-insensitive (RFC 9110 section 5.1), and HTTP/2 requires them to be lowercase (RFC 9113 section 8.2.1), so the server's chosen spelling is not something a client may key on. When a server sends `etag`, the lookup misses, `tableCache` is never populated, no later load sends `If-None-Match`, and the whole mechanism is inert -- with no error and nothing in the logs to suggest the server did answer with a tag.

This is not hypothetical. It is what happens against an Armeria-based catalog server, which writes HTTP/1 header names in their lowercase HTTP/2 form by default; I hit it while adding conditional `loadTable` support to Unity Catalog's Iceberg REST endpoints, where the server was returning a correct `ETag` that the client could not see. It also means the feature cannot work over HTTP/2 against any server, since lowercase names are mandatory there.

The fix is small: expose the response headers in a case-insensitive map, in `HTTPClient` where they are collected and in `RESTSessionCatalog` where they are copied.

### Willingness to contribute

- [x] I can contribute a fix for this bug independently

Contributor guide

Open the contributing guide

Research direction

Start in core/src/main/java/org/apache/iceberg/rest/HTTPClient.java at response header collection, then inspect the header copy and ETag lookup in core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java. Verify that lowercase and traditionally cased ETag headers both populate tableCache and allow later loads to use If-None-Match.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.