Skip to content

Bug: getParameters reports incorrect stack trace when transforms fails #3950

Open
@dreamorosi

Description

@dreamorosi

Expected Behavior

When receiving a TransformParameterError I should be able to see the correct stack trace that points me to where the error was thrown.

Current Behavior

The error thrown when there's a transform error in the getMultiple code path is wrapping the original TransformParameterError error in another instance of itself, mangling the stack trace and making it harder to identify the issue.

{
  "errorType": "TransformParameterError",
  "errorMessage": "Unable to transform value using 'auto' transform: Unable to transform value using 'auto' transform: Unexpected token 'm', \"my-parameter-value\" is not valid JSON",
  "name": "TransformParameterError",
  "stack": [
    "TransformParameterError: Unable to transform value using 'auto' transform: Unable to transform value using 'auto' transform: Unexpected token 'm', \"my-parameter-value\" is not valid JSON",
    "    at n.getMultiple (file:///var/task/index.mjs:2:6279)",
    "    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)",
    "    at async file:///var/task/index.mjs:2:10917"
  ]
}

should be something like (notice the correct transformValue location):

{
  "errorType": "TransformParameterError",
  "errorMessage": "Unable to transform value using 'auto' transform: Unexpected token 'm', \"my-parameter-value\" is not valid JSON",
  "name": "TransformParameterError",
  "stack": [
    "TransformParameterError: Unable to transform value using 'auto' transform: Unexpected token 'm', \"my-parameter-value\" is not valid JSON",
    "    at transformValue (/node_modules/@aws-lambda-powertools/parameters/lib/esm/base/transformValue.js:58:19)",
    "    at n.getMultiple (/node_modules/@aws-lambda-powertools/parameters/lib/esm/base/BaseProvider.js:126:40)",
    "    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)",
    "    at async <anonymous> (/src/index.ts:8:20)"
  ]
}

Code snippet

import { getStringFromEnv } from '@aws-lambda-powertools/commons/utils/env';
import { getParameters } from '@aws-lambda-powertools/parameters/ssm';

const parameterPrefix = getStringFromEnv({
  key: 'SSM_PARAMETER_PREFIX',
});

const parameters = await getParameters(parameterPrefix, {
  transform: 'auto',
  throwOnTransformError: true,
});

export const handler = async () => {
  console.log('Parameters:', parameters);
  return {
    statusCode: 200,
    body: JSON.stringify(parameters),
  };
};

Steps to Reproduce

  1. Deploy a stack with two parameters
Example
import { Stack, type StackProps, CfnOutput, RemovalPolicy } from 'aws-cdk-lib';
import type { Construct } from 'constructs';
import { Runtime, Tracing } from 'aws-cdk-lib/aws-lambda';
import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs';
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs';
import { StringParameter } from 'aws-cdk-lib/aws-ssm';
import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';

export class ParamsStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const fnName = 'ParamsFn';
    const logGroup = new LogGroup(this, 'MyLogGroup', {
      logGroupName: `/aws/lambda/${fnName}`,
      removalPolicy: RemovalPolicy.DESTROY,
      retention: RetentionDays.ONE_DAY,
    });

    const myParameter = new StringParameter(this, 'MySsmParameter', {
      parameterName: '/my/custom/parameter.json',
      stringValue: JSON.stringify({
        key1: 'value1',
      }),
      // You can specify other properties like description, tier, etc.
    });
    const myOtherParameter = new StringParameter(this, 'MyOtherSsmParameter', {
      parameterName: '/my/custom/parameter2.json',
      stringValue: 'my-parameter-value',
      // You can specify other properties like description, tier, etc.
    });

    const fn = new NodejsFunction(this, 'MyFunction', {
      functionName: fnName,
      logGroup,
      runtime: Runtime.NODEJS_20_X,
      entry: './src/index.ts',
      handler: 'handler',
      tracing: Tracing.ACTIVE,
      environment: {
        SSM_PARAMETER_PREFIX: '/my/custom/',
      },
      bundling: {
        minify: true,
        mainFields: ['module', 'main'],
        sourceMap: true,
        format: OutputFormat.ESM,
        banner:
          "import { createRequire } from 'module';const require = createRequire(import.meta.url);",
      },
    });
    fn.addToRolePolicy(
      new PolicyStatement({
        actions: ['ssm:GetParametersByPath'],
        resources: ['*'],
        effect: Effect.ALLOW,
      })
    );

    /* myParameter.grantRead(fn);
    myOtherParameter.grantRead(fn); */

    new CfnOutput(this, 'FunctionArn', {
      value: fn.functionArn,
    });
  }
}
  1. Add the function shown above
  2. Run it and observe the error formatting

Possible Solution

We should change this statement to just throw error.

Powertools for AWS Lambda (TypeScript) version

latest

AWS Lambda function runtime

22.x

Packaging format used

npm

Execution logs

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingconfirmedThe scope is clear, ready for implementationgood-first-issueSomething that is suitable for those who want to start contributinghelp-wantedWe would really appreciate some support from community for this oneparametersThis item relates to the Parameters Utility

Type

No type

Projects

Status

Working on it

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions