Skip to content

toolkit-lib: ValidationError thrown from deploy when Stack does not exist #954

@TheHolyWaffle

Description

@TheHolyWaffle

Describe the bug

I'm using @aws-cdk/toolkit-lib to deploy stacks programmatically.

As of recently, when bumping @aws-sdk/client-cloudformation to 3.938.0 these deploys started to fail with

{
  "$metadata" : {
    "httpStatusCode" : 400,
    "requestId" : "aac64c94-6168-4c3c-a080-eecfca52b5dd",
    "attempts" : 1,
    "totalRetryDelay" : 0
  },
  "$fault" : "client",
  "Type" : "Sender",
  "Code" : "ValidationError",
  "Error" : {
    "Type" : "Sender",
    "Code" : "ValidationError",
    "Message" : "Stack with id e2e-deploy-bert-degeyter does not exist"
  }
}

After some debugging, it appears that the Error object/structure has changed slightly, and this has a detrimental impact on stack-helpers.ts, more specifically these lines:

      if (e.name === 'ValidationError' && formatErrorMessage(e) === `Stack with id ${stackName} does not exist`) {
        return new CloudFormationStack(cfn, stackName, undefined);
      }

It appears that formatErrorMessage is not able to deal with these new errors being thrown from the updated cloudformation sdk client. Hence, the original error being forwarded and cdk.deploy(...) failing.

Image

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

deploy(...) should not fail when a Stack does not yet exist

Current Behavior

deploy(...) fails with the following error whenever a stack with a certain ID does not yet exist:

{
  "$metadata" : {
    "httpStatusCode" : 400,
    "requestId" : "aac64c94-6168-4c3c-a080-eecfca52b5dd",
    "attempts" : 1,
    "totalRetryDelay" : 0
  },
  "$fault" : "client",
  "Type" : "Sender",
  "Code" : "ValidationError",
  "Error" : {
    "Type" : "Sender",
    "Code" : "ValidationError",
    "Message" : "Stack with id e2e-deploy-bert-degeyter does not exist"
  }
}

Reproduction Steps

Use @aws-cdk/toolkit-lib v1.11.0 with @aws-sdk/client-cloudformation 3.938.0 installed alongside
Call CloudFormationStack.lookup() with a non-existent stack name
Observe that the ValidationError is thrown instead of returning a non-existent stack

Possible Solution

Update lib/util/format-error.js to handle AWS SDK v3 error structure:

function formatErrorMessage(error) {
    if (error && Array.isArray(error.errors)) {
        const innerMessages = error.errors
            .map((innerError) => (innerError?.message || innerError?.toString()))
            .join('\n');
        return `AggregateError: ${innerMessages}`;
    }
    
    if (toolkit_error_1.ToolkitError.isToolkitError(error) && error.cause) {
        return `${error.message}\n${formatErrorMessage(error.cause)}`;
    }
    
    // AWS SDK v3 structure: check error.Error.Message first
    if (error && typeof error === 'object' && 'Error' in error && 
        error.Error && typeof error.Error === 'object' && 'Message' in error.Error) {
        return error.Error.Message;
    }
    
    // Fallback for regular Error or other types
    return error?.message || error?.toString() || 'Unknown error';
}

Also update lib/api/cloudformation/stack-helper.js to remove the incorrect Error name check

static async lookup(cfn, stackName, retrieveProcessedTemplate = false) {
        try {
            const response = await cfn.describeStacks({ StackName: stackName });
            return new CloudFormationStack(cfn, stackName, response.Stacks && response.Stacks[0], retrieveProcessedTemplate);
        }
        catch (e) {
            const errorMessage = (0, util_1.formatErrorMessage)(e);
            if (errorMessage === `Stack with id ${stackName} does not exist`) { // Remove check on e.name === 'ValidationError'
                return new CloudFormationStack(cfn, stackName, undefined);
            }

            throw e;
        }
    }

Additional Information/Context

This issue affects all AWS SDK v3 service exceptions that use the nested Error.Message structure, not just ValidationError. The fix should be applied to ensure compatibility with AWS SDK v3 across all error types.

CDK CLI Version

xxx

Framework Version

1.11.0

Node.js Version

24.11.1

OS

MacOS 15.7.1

Language

TypeScript

Language Version

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions