Skip to content

Bug: UserAgentConfigurator hides a customer's AWS_SDK_UA_APP_ID environment variable #2725

Open

Description

@hidingmyname

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):

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

  1. Check out main at d767ff5.
  2. 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"), clearing sdk.ua.appId in @AfterEach.
  3. 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); current main 6455f45 differs only by docs dependency bumps and a powertools-batch MultiThreadMDC change, 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions