This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/master by this push:
new 29c6ea2372 CTR remove userAgent from connection options as per
previous devlist across all GLVs
29c6ea2372 is described below
commit 29c6ea2372ff624a36ece3a33549182e4af03acc
Author: Yang Xia <[email protected]>
AuthorDate: Wed Oct 21 18:31:09 2026 -0700
CTR remove userAgent from connection options as per previous devlist across
all GLVs
Removed the per-request userAgent request option from Java, Python, Go,
JavaScript and .NET. It was sent as a request body field that Gremlin
Server never read. The User-Agent header, controlled by
enableUserAgentOnConnect, is now the only place the user agent is sent.
Assisted-by: Kiro:claude-opus-5-5
---
CHANGELOG.asciidoc | 1 +
docs/src/reference/gremlin-variants.asciidoc | 16 ++++++++--------
docs/src/upgrade/release-4.x.x.asciidoc | 21 +++++++++++++++++++++
.../Gremlin.Net/Driver/Messages/RequestMessage.cs | 11 -----------
gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs | 6 ------
.../driver/remote/DriverRemoteConnectionTest.java | 1 -
gremlin-go/driver/client.go | 1 -
gremlin-go/driver/request.go | 14 --------------
gremlin-go/driver/requestOptions.go | 8 --------
gremlin-go/driver/requestOptions_test.go | 4 ----
gremlin-go/driver/request_test.go | 6 ------
gremlin-js/gremlin-javascript/lib/driver/client.ts | 1 -
.../lib/driver/driver-remote-connection.ts | 1 -
.../main/python/gremlin_python/driver/request.py | 2 +-
.../driver/test_driver_remote_connection.py | 1 -
.../org/apache/tinkerpop/gremlin/util/Tokens.java | 6 ------
16 files changed, 31 insertions(+), 69 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index de9c504422..0f9d34139f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -32,6 +32,7 @@
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Fixed a `NullPointerException` when rolling back a transaction on a
`TinkerStorageGraph` that has a vertex index but no edge index.
* Added a pluggable storage layer to `TinkerStorageGraph` that durably
persists each committed transaction to disk.
* Removed automatic persistence from `TinkerMemoryGraph`, which is now purely
in-memory and ignores `gremlin.tinkergraph.graphLocation`/`graphFormat`. Use
`TinkerStorageGraph` for durability or `g.io()` for interchange.
+* Removed the per-request `userAgent` option from all drivers so the user
agent is sent only as the `User-Agent` header controlled by
`enableUserAgentOnConnect`.
[[release-4-0-0-beta-3]]
=== TinkerPop 4.0.0-beta.3 (July 20, 2026)
diff --git a/docs/src/reference/gremlin-variants.asciidoc
b/docs/src/reference/gremlin-variants.asciidoc
index 70b88a0fb5..99de3c9d80 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -242,7 +242,7 @@ Some connection options can also be set on individual
requests made through the
results, err := g.With("timeoutMillis", 500).V().Out("knows").ToList()
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `userAgent` and
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults` and
`timeoutMillis`.
NOTE: When submitting traversals through `DriverRemoteConnection`,
`bulkResults` defaults to `true` per-request
@@ -531,7 +531,7 @@ options := new(RequestOptionsBuilder).
resultSet, err := client.SubmitWithOptions("g.V(x).count()", options)
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `userAgent`,
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`,
`timeoutMillis` and `materializeProperties`.
`RequestOptions` may also contain a map of query `parameters` to be applied to
the supplied
traversal string.
@@ -2012,7 +2012,7 @@ Some connection options can also be set on individual
requests made through the
const vertices = await g.with_('timeoutMillis', 500).V().out('knows').toList()
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `requestId`, `userAgent`,
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `requestId`,
`bulkResults`, `materializeProperties` and `timeoutMillis`.
NOTE: When submitting traversals through `DriverRemoteConnection`,
`bulkResults` defaults to `true` per-request
@@ -2360,7 +2360,7 @@ this feature is to set a per-request override to the
`timeoutMillis` so that it
const result = await client.submit("g.V().repeat(both()).times(100)", null, {
timeoutMillis: 5000 })
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `requestId`, `userAgent`,
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `requestId`,
`bulkResults`, `materializeProperties` and `timeoutMillis`.
IMPORTANT: The preferred method for setting a per-request timeout for scripts
is demonstrated above, but a script may
@@ -2764,7 +2764,7 @@ For instance to set request timeout to 500 milliseconds:
var l = g.With(Tokens.ArgsTimeoutMillis,
500).V().Out("knows").Count().ToList();
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `userAgent`,
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`,
`materializeProperties`, and `timeoutMillis`. These options are available as
constants on the `Gremlin.Net.Driver.Tokens`
class.
@@ -3039,7 +3039,7 @@ feature is to set a per-request override to the
`timeoutMillis` so that it only
include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithTimeout]
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `userAgent`, `materializeProperties`
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `materializeProperties`
and `timeoutMillis`. These options are available as constants on the
`Gremlin.Net.Driver.Tokens` class.
[[gremlin-dotnet-streaming]]
@@ -3473,7 +3473,7 @@ vertices = g.with_('timeoutMillis',
500).V().out('knows').to_list()
----
The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `language`,
-`materializeProperties`, `userAgent`, and `timeoutMillis`.
+`materializeProperties`, and `timeoutMillis`.
NOTE: When submitting traversals through `DriverRemoteConnection`,
`bulkResults` defaults to `True` per-request
to optimize result transfer. This does not apply to direct `Client.submit()`
calls, where `bulkResults` must be
@@ -3837,7 +3837,7 @@ this feature is to set a per-request override to the
`timeoutMillis` so that it
result_set = client.submit('g.V().repeat(both()).times(100)',
request_options={'timeoutMillis': 5000})
----
-The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `requestId`, `userAgent`,
+The following options are allowed on a per-request basis in this fashion:
`batchSize`, `bulkResults`, `requestId`,
`materializeProperties` and `timeoutMillis`.
IMPORTANT: The preferred method for setting a per-request timeout for scripts
is demonstrated above, but a script may
diff --git a/docs/src/upgrade/release-4.x.x.asciidoc
b/docs/src/upgrade/release-4.x.x.asciidoc
index 2222688b14..16e98aa801 100644
--- a/docs/src/upgrade/release-4.x.x.asciidoc
+++ b/docs/src/upgrade/release-4.x.x.asciidoc
@@ -149,6 +149,24 @@ which opens a `TinkerStorageGraph` with disk storage.
See:
link:https://tinkerpop.apache.org/docs/4.0.0/reference/#tinkergraph-gremlin-persistence[TinkerGraph
Persistence]
+==== User Agent Only in the Request Header
+
+The user agent is now sent only as the `User-Agent` HTTP header. Every driver
sends that header by default, and the
+connection-level `enableUserAgentOnConnect` option (cased idiomatically per
language) turns it on or off. The
+per-request `userAgent` field that some drivers could place in the request
body has been removed. Gremlin Server never
+read that field, so requests behave exactly as before.
+
+Code that set the per-request field no longer compiles or no longer has an
effect, and the line can simply be deleted:
+
+* Java: the unused `Tokens.ARGS_USER_AGENT` constant is removed.
+* Python: `userAgent` is no longer a recognized `request_options` key or
`with_()` option, and is ignored if supplied.
+* .NET: `RequestMessage.Builder.AddUserAgent()` and `Tokens.ArgsUserAgent` are
removed. `With("userAgent", ...)` is
+still forwarded like any other custom `With()` key, but Gremlin Server ignores
it.
+* Go: `RequestOptionsBuilder.SetUserAgent()` is removed, and
`With("userAgent", ...)` is ignored.
+* JavaScript: the `userAgent` field is removed from `RequestOptions`, and
`with_('userAgent', ...)` is ignored.
+
+See:
link:https://lists.apache.org/thread/clyxxp8t6mg3y7y8nj1z48l19j7pk2v8[\[DISCUSS\]
Only Support User Agent in Request Header]
+
=== Upgrading for Providers
==== Graph System Providers
@@ -162,6 +180,9 @@ the job of a `TinkerStorage` engine on `TinkerStorageGraph`.
==== Graph Driver Providers
+Drivers should send the user agent only as the `User-Agent` request header, in
the format described in the provider
+documentation, and should not add a `userAgent` field to the request body.
+
[llms-summary="Upgrade notes for the TinkerPop 4.0.0-beta.3 release:
user-facing changes including declarative pattern matching improvements and
other 4.0 features."]
== TinkerPop 4.0.0-beta.3
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs
b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs
index c99d046c8f..3290fe958a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs
@@ -202,17 +202,6 @@ namespace Gremlin.Net.Driver.Messages
return this;
}
- /// <summary>
- /// Sets the user agent for this request.
- /// </summary>
- /// <param name="userAgent">The user agent string.</param>
- /// <returns>The <see cref="Builder" />.</returns>
- public Builder AddUserAgent(string userAgent)
- {
- _fields[Tokens.ArgsUserAgent] = userAgent;
- return this;
- }
-
/// <summary>
/// Sets the bulk results option for this request.
/// </summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
b/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
index 2f1b330346..ff4b9ffda4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
@@ -57,12 +57,6 @@ namespace Gremlin.Net.Driver
/// </summary>
public const string ArgsGremlin = "gremlin";
- /// <summary>
- /// Argument name that allows a value that is a custom string that
the user can pass to a server that
- /// might accept it for purpose of identifying the kind of client
it came from.
- /// </summary>
- public const string ArgsUserAgent = "userAgent";
-
/// <summary>
/// Argument name that allows definition of the flavor of Gremlin
used (e.g. gremlin-groovy) to process the request.
/// </summary>
diff --git
a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
index 2d9e0a8d18..a0986fd24d 100644
---
a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
+++
b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
@@ -56,7 +56,6 @@ public class DriverRemoteConnectionTest {
with("y", 100).
with(Tokens.ARGS_BATCH_SIZE, 1000).
with(Tokens.TIMEOUT_MILLIS, 100000L).
- with(Tokens.ARGS_USER_AGENT, "test").
V().asAdmin().getGremlinLang());
assertEquals(1000, options.getBatchSize().get().intValue());
assertEquals(100000L, options.getTimeoutMillis().get().longValue());
diff --git a/gremlin-go/driver/client.go b/gremlin-go/driver/client.go
index d5345393ad..61144aeb00 100644
--- a/gremlin-go/driver/client.go
+++ b/gremlin-go/driver/client.go
@@ -326,7 +326,6 @@ func applyOptionsConfig(builder *RequestOptionsBuilder,
config map[string]interf
setterMap := map[string]string{
"timeoutMillis": "SetTimeoutMillis",
"batchSize": "SetBatchSize",
- "userAgent": "SetUserAgent",
"materializeProperties": "SetMaterializeProperties",
"bulkResults": "SetBulkResults",
}
diff --git a/gremlin-go/driver/request.go b/gremlin-go/driver/request.go
index cbe9f19e39..73dbc6d507 100644
--- a/gremlin-go/driver/request.go
+++ b/gremlin-go/driver/request.go
@@ -64,10 +64,6 @@ func MakeStringRequest(stringGremlin string, traversalSource
string, requestOpti
newFields["batchSize"] = requestOptions.batchSize
}
- if requestOptions.userAgent != "" {
- newFields["userAgent"] = requestOptions.userAgent
- }
-
if requestOptions.materializeProperties != "" {
newFields["materializeProperties"] =
requestOptions.materializeProperties
}
@@ -85,13 +81,3 @@ func MakeStringRequest(stringGremlin string, traversalSource
string, requestOpti
Fields: newFields,
}
}
-
-// allowedReqArgs contains the arguments that will be extracted from the
-// bytecode and sent with the request.
-var allowedReqArgs = map[string]bool{
- "timeoutMillis": true,
- "batchSize": true,
- "userAgent": true,
- "materializeProperties": true,
- "bulkResults": true,
-}
diff --git a/gremlin-go/driver/requestOptions.go
b/gremlin-go/driver/requestOptions.go
index cc65fb6c93..47a43740fc 100644
--- a/gremlin-go/driver/requestOptions.go
+++ b/gremlin-go/driver/requestOptions.go
@@ -22,7 +22,6 @@ package gremlingo
type RequestOptions struct {
timeoutMillis int
batchSize int
- userAgent string
parametersString string
materializeProperties string
bulkResults *bool
@@ -32,7 +31,6 @@ type RequestOptions struct {
type RequestOptionsBuilder struct {
timeoutMillis int
batchSize int
- userAgent string
parameters map[string]interface{}
parametersString string
materializeProperties string
@@ -50,11 +48,6 @@ func (builder *RequestOptionsBuilder) SetBatchSize(batchSize
int) *RequestOption
return builder
}
-func (builder *RequestOptionsBuilder) SetUserAgent(userAgent string)
*RequestOptionsBuilder {
- builder.userAgent = userAgent
- return builder
-}
-
func (builder *RequestOptionsBuilder) SetParameters(parameters
map[string]interface{}) *RequestOptionsBuilder {
if builder.parametersString != "" {
panic("cannot mix SetParameters() with SetParametersString()")
@@ -102,7 +95,6 @@ func (builder *RequestOptionsBuilder) Create()
RequestOptions {
requestOptions.timeoutMillis = builder.timeoutMillis
requestOptions.batchSize = builder.batchSize
- requestOptions.userAgent = builder.userAgent
requestOptions.materializeProperties = builder.materializeProperties
requestOptions.bulkResults = builder.bulkResults
requestOptions.transactionId = builder.transactionId
diff --git a/gremlin-go/driver/requestOptions_test.go
b/gremlin-go/driver/requestOptions_test.go
index 25b5408a3a..4e691322cb 100644
--- a/gremlin-go/driver/requestOptions_test.go
+++ b/gremlin-go/driver/requestOptions_test.go
@@ -34,10 +34,6 @@ func TestRequestOptions(t *testing.T) {
r := new(RequestOptionsBuilder).SetBatchSize(123).Create()
assert.Equal(t, 123, r.batchSize)
})
- t.Run("Test RequestOptionsBuilder with custom userAgent", func(t
*testing.T) {
- r :=
new(RequestOptionsBuilder).SetUserAgent("TestUserAgent").Create()
- assert.Equal(t, "TestUserAgent", r.userAgent)
- })
t.Run("Test RequestOptionsBuilder with custom materializeProperties",
func(t *testing.T) {
r :=
new(RequestOptionsBuilder).SetMaterializeProperties("TestMaterializeProperties").Create()
assert.Equal(t, "TestMaterializeProperties",
r.materializeProperties)
diff --git a/gremlin-go/driver/request_test.go
b/gremlin-go/driver/request_test.go
index ca75ac6415..46645943b0 100644
--- a/gremlin-go/driver/request_test.go
+++ b/gremlin-go/driver/request_test.go
@@ -46,12 +46,6 @@ func TestRequest(t *testing.T) {
assert.Equal(t, 123, r.Fields["batchSize"])
})
- t.Run("Test makeStringRequest() with custom userAgent", func(t
*testing.T) {
- r := MakeStringRequest("g.V()", "g",
-
new(RequestOptionsBuilder).SetUserAgent("TestUserAgent").Create())
- assert.Equal(t, "TestUserAgent", r.Fields["userAgent"])
- })
-
t.Run("Test makeStringRequest() with bulkResults", func(t *testing.T) {
r := MakeStringRequest("g.V()", "g",
new(RequestOptionsBuilder).SetBulkResults(true).Create())
diff --git a/gremlin-js/gremlin-javascript/lib/driver/client.ts
b/gremlin-js/gremlin-javascript/lib/driver/client.ts
index 0686d4d0e8..cd7893cb6d 100644
--- a/gremlin-js/gremlin-javascript/lib/driver/client.ts
+++ b/gremlin-js/gremlin-javascript/lib/driver/client.ts
@@ -27,7 +27,6 @@ export type RequestOptions = {
accept?: string;
timeoutMillis?: number;
batchSize?: number;
- userAgent?: string;
materializeProperties?: string;
bulkResults?: boolean;
params?: Record<string, any>;
diff --git
a/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts
b/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts
index d61fde3fd4..af6c18fcf3 100644
--- a/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts
+++ b/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts
@@ -84,7 +84,6 @@ export default class DriverRemoteConnection extends
RemoteConnection {
'timeoutMillis',
'batchSize',
'requestId',
- 'userAgent',
'materializeProperties',
'bulkResults',
];
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/request.py
b/gremlin-python/src/main/python/gremlin_python/driver/request.py
index 0b72fa1aa6..4e75ffb8f8 100644
--- a/gremlin-python/src/main/python/gremlin_python/driver/request.py
+++ b/gremlin-python/src/main/python/gremlin_python/driver/request.py
@@ -24,5 +24,5 @@ RequestMessage = collections.namedtuple(
'RequestMessage', ['fields', 'gremlin'])
Tokens = ['batchSize', 'parameters', 'g', 'gremlin', 'language',
- 'materializeProperties', 'timeoutMillis', 'userAgent', 'bulkResults',
+ 'materializeProperties', 'timeoutMillis', 'bulkResults',
'transactionId']
diff --git
a/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
b/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
index 61279f34f2..adf131866d 100644
---
a/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
+++
b/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
@@ -60,7 +60,6 @@ class TestDriverRemoteConnection(object):
"test").V(GValue('ids', [1, 2, 3])).count()
assert remote_connection.extract_request_options(t.gremlin_lang) ==
{'batchSize': 100,
'timeoutMillis': 1000,
-
'userAgent': 'test',
'bulkResults': True,
'parameters': "['ids':[1,2,3]]"}
assert 3 == t.to_list()[0]
diff --git
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
index e4acba5d55..27a110d259 100644
--- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
@@ -97,12 +97,6 @@ public final class Tokens {
*/
public static final String BULK_RESULTS = "bulkResults";
- /**
- * A value that is a custom string that the user can pass to a server that
might accept it for purpose of
- * identifying the kind of client it came from.
- */
- public static final String ARGS_USER_AGENT = "userAgent";
-
/**
* Argument name for the transaction ID used to track multi-request
transactions over HTTP.
* The transaction ID is a UUID generated by the client at transaction
begin time and included