Skip to content

OpenAPI: Recommend a standard User-Agent format for REST clients - #17727

Merged
laskoviymishka merged 9 commits into
apache:mainfrom
rahulsmahadev:rest-user-agent-proposal
Nov 10, 2026
Merged

laskoviymishka merged 9 commits into
apache:mainfrom
rahulsmahadev:rest-user-agent-proposal

Conversation

@rahulsmahadev

@rahulsmahadev rahulsmahadev commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds a recommended, consistent User-Agent format to the REST spec so clients identify themselves the same way, and documents that client identification is optional and informational only.

Spec-only proposal

Why

Clients identify themselves inconsistently today, and the most-deployed one doesn't by default:

Client User-Agent X-Client-Version
iceberg-java none by default (opt-in rest.client.user-agent) Apache Iceberg <ver> (commit <sha>) — library version
pyiceberg PyIceberg/<ver> PyIceberg <ver> — library version
iceberg-rust iceberg-rs/<ver> 0.14.1 — REST spec version
iceberg-go GoIceberg/<ver> REST spec version

A catalog operator can't reliably tell what's calling: the Java client sends no User-Agent unless configured, the naming differs across clients, and X-Client-Version carries the library version in two clients and the spec version in the other two. None of it is described in the spec.

A single recommended format gives operators usable telemetry for observability, debugging, and support, and an Iceberg library token that's always present regardless of the embedding engine.

Proposal

Use the standard User-Agent header (RFC 7231): whitespace-separated product/version tokens, most-specific first (engine → integration → Iceberg library → runtime), with a parenthesized comment as an open extension point.

Spark/4.0.0 iceberg-spark/1.9.0 iceberg-java/1.9.0 (scala/2.13.16)
  • The Iceberg library token (iceberg-java, pyiceberg, iceberg-rust, iceberg-go) is the piece every client can supply and should always be present.
  • Optional and informational: servers must not reject on missing/malformed, must not use it for auth or trust decisions, and it is not capability negotiation — that's the versioned-endpoints discussion from Core, OpenApi: Add X-Iceberg-Client-Capabilities header #16394, kept deliberately separate.

Scope / follow-ups

This PR is the spec recommendation. If the format lands, client conformance follows as separate PRs:

  • iceberg-java: give rest.client.user-agent a default library token and a way for integrations (Spark/Flink/…) to contribute engine tokens.
  • pyiceberg / iceberg-rust / iceberg-go: emit the same format.

@rahulsmahadev
rahulsmahadev marked this pull request as ready for review August 19, 2026 23:54
@singhpk234

Copy link
Copy Markdown
Contributor

This is a nice addition, can you please open a dev DISCUSS thread as well !

@singhpk234
singhpk234 self-requested a review August 21, 2026 06:12
@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

@singhpk234 thanks! Opened a DISCUSS thread on the dev list: https://lists.apache.org/thread/d6hkx66o8qc1lolh11l1lmswxlq0bpj9

Comment thread open-api/rest-catalog-open-api.yaml Outdated
Examples:


`pyiceberg/0.11.0 (cpython/3.11.4)` — a client library used directly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, does the RFC accept product identifiers surrounded by parentheses?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — no, the parens are an RFC comment, not product tokens. The runtime bits belong there as free-form context. Clarified the wording and fixed the examples so the parenthesized part reads as a comment (e.g. (jvm 17.0.9)).

Comment thread open-api/rest-catalog-open-api.yaml Resolved
Comment thread open-api/rest-catalog-open-api.yaml Resolved
Comment thread open-api/rest-catalog-open-api.yaml Outdated
Recommended library tokens are `iceberg-java`, `pyiceberg`,
`iceberg-rust`, and `iceberg-go`.
then any integration or connector, then the Iceberg library, then the
language runtime.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Language runtime is mentioned twice: here as a product token, then below (line 2212) as a comment. I think the final intent is to move language runtime info to comments.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread open-api/rest-catalog-open-api.yaml Resolved
Comment thread open-api/rest-catalog-open-api.yaml Outdated
and MUST NOT depend on its contents.
The optional trailing comment, enclosed in parentheses as defined by
the RFC, carries lower-value context such as build identifiers, the
HTTP library, the language runtime, or the operating system. Everything

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to clarify:

  1. whether all of these items should appear in different comments, or together in a single one, or both? E.g.
(apache-http 5.0; jvm 17.0.9; ubuntu 26.04)
(apache-http 5.0) (jvm 17.0.9) (ubuntu 26.04)
  1. whether comments can appear interleaved with products, or only at the end after the products.

The RFC allows all of the above, but maybe we could restrict the expected format to facilitate parsing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clarified

Comment thread open-api/rest-catalog-open-api.yaml Resolved

@rahulsmahadev rahulsmahadev left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @adutra Thanks for your feedback so far, addressed your comments lmk if it looks better, I can re-open the voting once we are in agreement on this PR

@rahulsmahadev
rahulsmahadev force-pushed the rest-user-agent-proposal branch from 617b0d5 to 5943e8f Compare September 30, 2026 05:36
@adutra

adutra commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Thanks @rahulsmahadev LGTM!

@sungwy

sungwy commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR @rahulsmahadev - it looks like the CI is failing due to CVE-2026-68497 (#18318)

Could you please rebase it on main and let the CI run one more time?

Comment thread open-api/rest-catalog-open-api.yaml Resolved
Comment thread open-api/rest-catalog-open-api.yaml Resolved
@manuzhang

Copy link
Copy Markdown
Member

@rahulsmahadev please rebase to fix CVE failures.

Adds a recommended, consistent User-Agent format to the REST spec so
clients identify themselves the same way, and documents that client
identification is optional and informational only (not authentication,
not capability negotiation).

Spec-only; no behavior change. Client libraries would be updated to emit
this format as follow-ups.
- Require the Iceberg library token when the header is sent, and make the
  format normative rather than "recommended".
- Clarify that the parenthesized part is a free-form RFC comment, not a
  product token, and update the examples accordingly.
- Allow servers to refuse operations from client versions known to be
  unsafe (e.g. corrupt statistics), while still not rejecting merely on a
  missing or malformed header.
…nt format

Address review feedback on the client User-Agent parameter: make the Iceberg library list illustrative rather than exhaustive (add iceberg-cpp, note proprietary or custom implementations use their own product token); drop the language runtime from the product-token ordering since it belongs in the trailing comment; and recommend grouping context items into a single trailing comment placed after all product tokens, semicolon-separated.
Clarify that refusing a known-bad client version applies only to a header
that names that version, and is not an exception to the rule that an
absent or malformed header is not a reason to refuse a request. Add an
example with both a runtime and an operating system, and show that the
comment format extends to any number of items.
@rahulsmahadev
rahulsmahadev force-pushed the rest-user-agent-proposal branch from 5943e8f to 5534ff9 Compare October 9, 2026 00:56
@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

@rahulsmahadev please rebase to fix CVE failures.

Done

@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

@singhpk234 and @openinx can I get a review

@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

Friendly ping for review @manuzhang @singhpk234 @openinx

The user-agent header parameter was not referenced by any operation, so
renderers dropped it. Fold its format rules into the Client Identification
section, cite RFC 9110, and clarify the token order, how a server finds
the library token, the capability negotiation rule, and how a server
refuses a known-bad client version.
@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

@manuzhang addressed your comments, PTAL

@openinx

openinx commented Oct 28, 2026

Copy link
Copy Markdown
Member

Approved, but I will wait @manuzhang @singhpk234 for the approval before I merge it. thanks @rahulsmahadev for the work.

@manuzhang

Copy link
Copy Markdown
Member

LGTM. Thanks for the PR.

@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

Thanks @openinx and @manuzhang! @singhpk234, could you take a look when you get a chance?

@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

@openinx manuzhang has LGTM'd, and singhpk234 hasn't had a chance yet. Would you be OK merging this?

Comment thread open-api/rest-catalog-open-api.yaml Outdated
Comment on lines +43 to +45
- When the header is sent, the token of the Iceberg client library MUST be
present, for example `iceberg-java`, `pyiceberg`, `iceberg-rust`,
`iceberg-go`, or `iceberg-cpp`. This list is illustrative, not

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already released client don't send iceberg-java in the UA what we observe is Apache HTTP client version ? this should be a SHOULD right considering already released SDK

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, released clients don't send it. Today the Java client only sets a User-Agent when rest.client.user-agent is configured, so servers see the Apache HttpClient default (they can still identify old Java clients from the X-Client-Version header). The spec can't change what's already shipped, which is why the advisory rules say servers SHOULD NOT reject a request whose header is absent, incomplete, or malformed. The MUST is for clients that follow this format from now on, so a server can always rely on the library token being there. With a SHOULD, it couldn't rely on it even for new clients. This is also the wording the vote passed on. The client changes that add the token (Java, Python, Go, Rust) are ready and will go out once this merges.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MUST is for clients that follow this format from now on, so a server can always rely on the library token being there

I am not sure how does this literature defines now on for example there are already released version of the SDK which this MUST puts it into questionable situation in past we have taken same stance please ref #16822 (comment) @nastra thoughts ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point, and #16822 is a good precedent. Changed it to SHOULD. The Java, Python, Go and Rust clients will all send the token once their follow-up changes land, so servers will still see it in practice.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I agree, it should be updated to SHOULD

@singhpk234 singhpk234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the ping @rahulsmahadev !
added some comments inline

Comment thread open-api/rest-catalog-open-api.yaml Resolved
Released clients do not send the library token, so a MUST would leave
them out of compliance. apache#16822 made a similar client rule a SHOULD for
the same reason.

Co-authored-by: Isaac <[email protected]>
Comment thread open-api/rest-catalog-open-api.yaml Outdated
advertise the protocol features they support, and servers MUST NOT infer
from it which features a client supports. Servers advertise the
endpoints they support in the `endpoints` field of the config response.
- Servers MAY refuse specific operations when the header identifies a

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should have this statement here. Isn't the header purely informational?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This came from Dan's review (#17727 (comment)): a catalog should be able to block a client version known to have a critical bug, for example one that writes corrupt statistics. It was also part of the text we voted on. The header is informational for everything else, and this is kept narrow: it's a MAY, it only applies when the header names a known-bad version, and an absent or malformed header is never a reason to refuse. @danielcweeks can you weigh in?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @nastra here. We can just remove the language. We don't want to say servers can/can't do anything with it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Dan agreed it's over-specifying, so I removed it.

The spec does not need to say when a server may refuse a request, so the
rule only over-specified server behavior.

Co-authored-by: Isaac <[email protected]>
Comment thread open-api/rest-catalog-open-api.yaml Outdated
system. These items SHOULD be grouped into a single comment after all
product tokens and separated by `; `, for example
`(jvm 17.0.9; ubuntu 26.04)` or
`(cpython 3.11.4; urllib3 2.2.1; macos 15.1)`. The comment is free-form:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I feel like the second example should fit into the previous line

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@rahulsmahadev

Copy link
Copy Markdown
Contributor Author

@openinx nastra and Prashant have approved now. Since the vote, the text changed in two ways, both loosening it: the library token went from MUST to SHOULD, and the rule letting servers refuse known-bad versions is gone. Would you be OK merging this?

@szehon-ho szehon-ho left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes sense to me, the format is now pretty clear (space delimited and then comment in parens). will merge if no other comments!

@laskoviymishka laskoviymishka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vote passed, it's ready to merge

@laskoviymishka
laskoviymishka merged commit 0d07c41 into apache:main Nov 10, 2026
24 checks passed
dekelpilli pushed a commit to core0-io/iceberg-rust that referenced this pull request Nov 11, 2026
…3668)

The REST catalog spec recommends a standard User-Agent format whose
library token for Rust is iceberg-rust (apache/iceberg#17727), so send
iceberg-rust/<version> instead of iceberg-rs/<version>. A header.user-agent
property still overrides the default.
laskoviymishka pushed a commit to apache/iceberg-go that referenced this pull request Nov 11, 2026
Send iceberg-go/<version> (go <go version>) as the default User-Agent,
following the format recommended by the REST catalog spec
(apache/iceberg#17727). Headers configured by the caller still take
precedence over the default.
hcrosse pushed a commit to hcrosse/iceberg-python that referenced this pull request Nov 11, 2026
* REST: Use the standard User-Agent format

Send pyiceberg/<version> (<python implementation> <python version>), for
example pyiceberg/0.11.0 (cpython 3.11.4), the format recommended by the
REST catalog spec (apache/iceberg#17727).

Co-authored-by: Isaac <[email protected]>

* Use a loop for User-Agent test cases

Co-authored-by: Copilot App <[email protected]>

---------

Co-authored-by: Isaac <[email protected]>
Co-authored-by: Fokko Driesprong <[email protected]>
Co-authored-by: Kevin Liu <[email protected]>
Co-authored-by: Copilot App <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants