Repository navigation
Bug: UserAgentConfigurator hides a customer's AWS_SDK_UA_APP_ID environment variable #2725
Description
Expected Behaviour
When a function sets the AWS SDK application ID through the AWS_SDK_UA_APP_ID environment variable, enabling Powertools should keep that customer ID in the effective app ID (with the Powertools identifier added), the same way it already does when the ID is set through the sdk.ua.appId system property. The configureUserAgent Javadoc states it "Preserves any user-provided value".
Current Behaviour
Location (aws-powertools/powertools-lambda-java @ default branch 6455f45):
UserAgentConfigurator.java:89-107—configureUserAgentreads only thesdk.ua.appIdsystem property as the existing value, then writes its own value into that property.UserAgentConfigurator.java:84-89— Javadoc: "Preserves any user-provided value".
Current code:
public static void configureUserAgent(String ptFeature) {
try {
String existingValue = System.getProperty(SDK_USER_AGENT_APP_ID);
String powertoolsUserAgent = getUserAgent(ptFeature);
String newValue;
if (existingValue == null || existingValue.isEmpty()) {
newValue = powertoolsUserAgent;
} else {
String userValue = extractUserValue(existingValue);
if (userValue.isEmpty()) {
newValue = powertoolsUserAgent;
} else {
newValue = userValue + "/" + powertoolsUserAgent;
}
}
if (newValue.length() <= 50) {
System.setProperty(SDK_USER_AGENT_APP_ID, newValue);Problem: configureUserAgent never looks at the AWS_SDK_UA_APP_ID environment variable. Per the AWS SDKs and Tools reference, the JVM system property takes precedence over the environment variable (settings precedence, application ID — both settings are supported by the Java SDK v2). So once Powertools sets the property, a customer ID configured through the environment variable is no longer the effective value: with AWS_SDK_UA_APP_ID=CUSTOMER_VALUE, the property becomes PT/TEST-FEATURE/2.11.0 PTENV/NA instead of CUSTOMER_VALUE/PT/TEST-FEATURE/2.11.0 PTENV/NA.
Scope note: I verified the resulting system property value; I did not capture an actual SDK request's User-Agent header.
Code snippet
// run with environment variable AWS_SDK_UA_APP_ID=CUSTOMER_VALUE and sdk.ua.appId unset
System.clearProperty("sdk.ua.appId");
UserAgentConfigurator.configureUserAgent("test-feature");
assertThat(System.getProperty("sdk.ua.appId"))
.startsWith("CUSTOMER_VALUE/"); // fails: "PT/TEST-FEATURE/2.11.0 PTENV/NA"(In the test I used junit-pioneer's @SetEnvironmentVariable(key = "AWS_SDK_UA_APP_ID", value = "CUSTOMER_VALUE"), which this repo already uses.)
Steps to Reproduce
Reproduction
- Check out
mainatd767ff5. - Add the snippet as a test in
powertools-common/src/test/java/software/amazon/lambda/powertools/common/internal/with@SetEnvironmentVariable(key = "AWS_SDK_UA_APP_ID", value = "CUSTOMER_VALUE"), clearingsdk.ua.appIdin@AfterEach. mvn -pl powertools-common -am test -Dtest=<TestClass> -Dsurefire.failIfNoSpecifiedTests=false
Failing output:
expected: "CUSTOMER_VALUE/PT/TEST-FEATURE/2.11.0 PTENV/NA"
but was: "PT/TEST-FEATURE/2.11.0 PTENV/NA"Environment:
- Commit:
d767ff5(main); currentmain6455f45differs only by docs dependency bumps and apowertools-batchMultiThreadMDCchange, so the code paths above are unchanged. - Toolchain: OpenJDK 25.0.5, Apache Maven 3.9.16 (unit test, not deployed to Lambda)
Possible Solution
Already fixed in aws-powertools/powertools-lambda-typescript
PR: aws-powertools/powertools-lambda-typescript#4374 — "chore(commons): concatenate PT UA to AWS_SDK_UA_APP_ID when one is set" (merged 2025-08-22T17:41:51Z, merge commit 519cbfe99db).
The TypeScript runtime previously only set its identifier when AWS_SDK_UA_APP_ID was empty; the new else branch keeps a customer-provided AWS_SDK_UA_APP_ID and appends the Powertools identifier to it.
How powertools-lambda-typescript fixed it:
--- a/packages/commons/src/index.ts
+++ b/packages/commons/src/index.ts
@@ -1,7 +1,9 @@
import { PT_VERSION } from './version.js';
if (!process.env.AWS_SDK_UA_APP_ID) {
- process.env.AWS_SDK_UA_APP_ID = `PT/NO-OP/${PT_VERSION}`;
+ process.env.AWS_SDK_UA_APP_ID = `PT/TEST/${PT_VERSION}`;
+} else {
+ process.env.AWS_SDK_UA_APP_ID = `${process.env.AWS_SDK_UA_APP_ID}/PT/TEST/${PT_VERSION}`;
}
export { addUserAgentMiddleware, isSdkClient } from './awsSdkUtils.js';Suggested fix
When the sdk.ua.appId system property is unset or empty, fall back to the AWS_SDK_UA_APP_ID environment variable as the existing user value; the rest of the logic (stripping a previous Powertools suffix, appending the Powertools identifier, the 50-character limit) is unchanged, and an explicitly set system property keeps taking precedence:
diff --git a/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java b/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java
--- a/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java
+++ b/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java
@@ -35,6 +35,7 @@ public final class UserAgentConfigurator {
public static final String VERSION_PROPERTIES_FILENAME = "version.properties";
public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV";
private static final String SDK_USER_AGENT_APP_ID = "sdk.ua.appId";
+ private static final String SDK_USER_AGENT_APP_ID_ENV = "AWS_SDK_UA_APP_ID";
private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class);
private static final String NO_OP = "no-op";
private static final String POWERTOOLS_VERSION = getProjectVersion();
@@ -82,13 +83,17 @@ public final class UserAgentConfigurator {
/**
* Configures the AWS SDK to use Powertools user agent by setting the sdk.ua.appId system property.
- * Preserves any user-provided value and replaces any existing Powertools user agent.
+ * Preserves any user-provided value (from the sdk.ua.appId system property or, if unset, the AWS_SDK_UA_APP_ID
+ * environment variable) and replaces any existing Powertools user agent.
* Enforces a 50 character limit to comply with AWS SDK recommendations.
* This should be called during library initialization to ensure the user agent is properly configured.
*/
public static void configureUserAgent(String ptFeature) {
try {
String existingValue = System.getProperty(SDK_USER_AGENT_APP_ID);
+ if (existingValue == null || existingValue.isEmpty()) {
+ existingValue = System.getenv(SDK_USER_AGENT_APP_ID_ENV);
+ }
String powertoolsUserAgent = getUserAgent(ptFeature);
String newValue;
Verified on d767ff5 (OpenJDK 25.0.5, Maven 3.9.16): the test above fails without this patch and passes with it; no other test results change.
I can submit a PR for this.
Powertools for AWS Lambda (Java) version
2.11.0 (main at d767ff5; same code on current main 6455f45)
AWS Lambda function runtime
Java 25 (reproduced as a unit test on OpenJDK 25.0.5, Apache Maven 3.9.16 — not deployed to Lambda)
Debugging logs
See the failing output under Steps to Reproduce.
Related issues checked
Checked: #2086 (introduced setting sdk.ua.appId) and #1306 (original UA suffix) do not cover the environment variable.
Activity