Skip to content

Commit 6ccdd81

Browse files
authored
feat(lambda): throw ValidationErrors instead of untyped errors (#34577)
### Issue Relates to #32569 ### Reason for this change untyped Errors are not recommended ### Description of changes `ValidationError`s everywhere ### Describe any new or updated permissions being added None ### Description of how you validated changes Existing tests. Exemptions granted as this is a refactor of existing code. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent d513554 commit 6ccdd81

File tree

11 files changed

+73
-72
lines changed

11 files changed

+73
-72
lines changed

packages/aws-cdk-lib/.eslintrc.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ baseConfig.rules['@cdklabs/no-throw-default-error'] = ['error'];
1818
// not yet supported
1919
const noThrowDefaultErrorNotYetSupported = [
2020
'aws-iam',
21-
'aws-lambda-destinations',
22-
'aws-lambda-event-sources',
23-
'aws-lambda-nodejs',
2421
'aws-secretsmanager',
2522
'aws-servicecatalog',
2623
'core',

packages/aws-cdk-lib/aws-lambda-destinations/lib/lambda.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { EventBridgeDestination } from './event-bridge';
33
import * as events from '../../aws-events';
44
import * as targets from '../../aws-events-targets';
55
import * as lambda from '../../aws-lambda';
6+
import { ValidationError } from '../../core';
67

78
/**
89
* Options for a Lambda destination
@@ -49,7 +50,7 @@ export class LambdaDestination implements lambda.IDestination {
4950
// Otherwise add rule to extract the response payload and use EventBridge
5051
// as destination
5152
if (!options) { // `options` added to bind() as optionnal to avoid breaking change
52-
throw new Error('Options must be defined when using `responseOnly`.');
53+
throw new ValidationError('Options must be defined when using `responseOnly`.', scope);
5354
}
5455

5556
// Match invocation result of the source function (`fn`) and use it

packages/aws-cdk-lib/aws-lambda-event-sources/lib/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as apigw from '../../aws-apigateway';
22
import * as lambda from '../../aws-lambda';
3-
import { Names, Stack } from '../../core';
3+
import { Names, Stack, UnscopedValidationError } from '../../core';
44

55
export class ApiEventSource implements lambda.IEventSource {
66
constructor(private readonly method: string, private readonly path: string, private readonly options?: apigw.MethodOptions) {
77
if (!path.startsWith('/')) {
8-
throw new Error(`Path must start with "/": ${path}`);
8+
throw new UnscopedValidationError(`Path must start with "/": ${path}`);
99
}
1010
}
1111

packages/aws-cdk-lib/aws-lambda-event-sources/lib/dynamodb.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { StreamEventSource, StreamEventSourceProps } from './stream';
22
import * as dynamodb from '../../aws-dynamodb';
33
import * as lambda from '../../aws-lambda';
4-
import { Names, Token } from '../../core';
4+
import { Names, Token, ValidationError } from '../../core';
55

66
export interface DynamoEventSourceProps extends StreamEventSourceProps {
77
}
@@ -19,13 +19,13 @@ export class DynamoEventSource extends StreamEventSource {
1919
if (this.props.batchSize !== undefined
2020
&& !Token.isUnresolved(this.props.batchSize)
2121
&& (this.props.batchSize < 1 || this.props.batchSize > 10000)) {
22-
throw new Error(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize})`);
22+
throw new ValidationError(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize})`, table);
2323
}
2424
}
2525

2626
public bind(target: lambda.IFunction) {
2727
if (!this.table.tableStreamArn) {
28-
throw new Error(`DynamoDB Streams must be enabled on the table ${this.table.node.path}`);
28+
throw new ValidationError(`DynamoDB Streams must be enabled on the table ${this.table.node.path}`, this.table);
2929
}
3030

3131
const eventSourceMapping = target.addEventSourceMapping(`DynamoDBEventSource:${Names.nodeUniqueId(this.table.node)}`,
@@ -46,7 +46,7 @@ export class DynamoEventSource extends StreamEventSource {
4646
*/
4747
public get eventSourceMappingId(): string {
4848
if (!this._eventSourceMappingId) {
49-
throw new Error('DynamoEventSource is not yet bound to an event source mapping');
49+
throw new ValidationError('DynamoEventSource is not yet bound to an event source mapping', this.table);
5050
}
5151
return this._eventSourceMappingId;
5252
}
@@ -56,7 +56,7 @@ export class DynamoEventSource extends StreamEventSource {
5656
*/
5757
public get eventSourceMappingArn(): string {
5858
if (!this._eventSourceMappingArn) {
59-
throw new Error('DynamoEventSource is not yet bound to an event source mapping');
59+
throw new ValidationError('DynamoEventSource is not yet bound to an event source mapping', this.table);
6060
}
6161
return this._eventSourceMappingArn;
6262
}

packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as iam from '../../aws-iam';
55
import { IKey } from '../../aws-kms';
66
import * as lambda from '../../aws-lambda';
77
import * as secretsmanager from '../../aws-secretsmanager';
8-
import { Stack, Names, Annotations } from '../../core';
8+
import { Stack, Names, Annotations, UnscopedValidationError, ValidationError } from '../../core';
99
import { md5hash } from '../../core/lib/helpers-internal';
1010

1111
/**
@@ -221,7 +221,7 @@ export class ManagedKafkaEventSource extends StreamEventSource {
221221
*/
222222
public get eventSourceMappingId(): string {
223223
if (!this._eventSourceMappingId) {
224-
throw new Error('KafkaEventSource is not yet bound to an event source mapping');
224+
throw new UnscopedValidationError('KafkaEventSource is not yet bound to an event source mapping');
225225
}
226226
return this._eventSourceMappingId;
227227
}
@@ -231,7 +231,7 @@ export class ManagedKafkaEventSource extends StreamEventSource {
231231
*/
232232
public get eventSourceMappingArn(): string {
233233
if (!this._eventSourceMappingArn) {
234-
throw new Error('KafkaEventSource is not yet bound to an event source mapping');
234+
throw new UnscopedValidationError('KafkaEventSource is not yet bound to an event source mapping');
235235
}
236236
return this._eventSourceMappingArn;
237237
}
@@ -248,28 +248,28 @@ export class SelfManagedKafkaEventSource extends StreamEventSource {
248248
super(props);
249249
if (props.vpc) {
250250
if (!props.securityGroup) {
251-
throw new Error('securityGroup must be set when providing vpc');
251+
throw new UnscopedValidationError('securityGroup must be set when providing vpc');
252252
}
253253
if (!props.vpcSubnets) {
254-
throw new Error('vpcSubnets must be set when providing vpc');
254+
throw new UnscopedValidationError('vpcSubnets must be set when providing vpc');
255255
}
256256
} else if (!props.secret) {
257-
throw new Error('secret must be set if Kafka brokers accessed over Internet');
257+
throw new UnscopedValidationError('secret must be set if Kafka brokers accessed over Internet');
258258
}
259259

260260
if (props.startingPosition === lambda.StartingPosition.AT_TIMESTAMP && !props.startingPositionTimestamp) {
261-
throw new Error('startingPositionTimestamp must be provided when startingPosition is AT_TIMESTAMP');
261+
throw new UnscopedValidationError('startingPositionTimestamp must be provided when startingPosition is AT_TIMESTAMP');
262262
}
263263

264264
if (props.startingPosition !== lambda.StartingPosition.AT_TIMESTAMP && props.startingPositionTimestamp) {
265-
throw new Error('startingPositionTimestamp can only be used when startingPosition is AT_TIMESTAMP');
265+
throw new UnscopedValidationError('startingPositionTimestamp can only be used when startingPosition is AT_TIMESTAMP');
266266
}
267267

268268
this.innerProps = props;
269269
}
270270

271271
public bind(target: lambda.IFunction) {
272-
if (!(Construct.isConstruct(target))) { throw new Error('Function is not a construct. Unexpected error.'); }
272+
if (!(Construct.isConstruct(target))) { throw new ValidationError('Function is not a construct. Unexpected error.', target); }
273273
target.addEventSourceMapping(
274274
this.mappingId(target),
275275
this.enrichMappingOptions({

packages/aws-cdk-lib/aws-lambda-event-sources/lib/kinesis.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as iam from '../../aws-iam';
44
import * as kinesis from '../../aws-kinesis';
55
import * as lambda from '../../aws-lambda';
66
import * as cdk from '../../core';
7+
import { UnscopedValidationError } from '../../core';
78

89
export interface KinesisEventSourceProps extends StreamEventSourceProps {
910
/**
@@ -38,7 +39,7 @@ abstract class KinesisEventSourceBase extends StreamEventSource {
3839

3940
this.props.batchSize !== undefined && cdk.withResolved(this.props.batchSize, batchSize => {
4041
if (batchSize < 1 || batchSize > 10000) {
41-
throw new Error(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize})`);
42+
throw new UnscopedValidationError(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize})`);
4243
}
4344
});
4445
}
@@ -63,7 +64,7 @@ abstract class KinesisEventSourceBase extends StreamEventSource {
6364
*/
6465
public get eventSourceMappingId(): string {
6566
if (!this._eventSourceMappingId) {
66-
throw new Error(`${this.source.eventSourceName} is not yet bound to an event source mapping`);
67+
throw new UnscopedValidationError(`${this.source.eventSourceName} is not yet bound to an event source mapping`);
6768
}
6869
return this._eventSourceMappingId;
6970
}
@@ -73,7 +74,7 @@ abstract class KinesisEventSourceBase extends StreamEventSource {
7374
*/
7475
public get eventSourceMappingArn(): string {
7576
if (!this._eventSourceMappingArn) {
76-
throw new Error(`${this.source.eventSourceName} is not yet bound to an event source mapping`);
77+
throw new UnscopedValidationError(`${this.source.eventSourceName} is not yet bound to an event source mapping`);
7778
}
7879
return this._eventSourceMappingArn;
7980
}

packages/aws-cdk-lib/aws-lambda-event-sources/lib/sqs.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { IKey } from '../../aws-kms';
22
import * as lambda from '../../aws-lambda';
33
import * as sqs from '../../aws-sqs';
4-
import { Duration, Names, Token, Annotations } from '../../core';
4+
import { Duration, Names, Token, Annotations, ValidationError } from '../../core';
55

66
export interface SqsEventSourceProps {
77
/**
@@ -88,18 +88,18 @@ export class SqsEventSource implements lambda.IEventSource {
8888
constructor(readonly queue: sqs.IQueue, private readonly props: SqsEventSourceProps = { }) {
8989
if (this.props.maxBatchingWindow !== undefined) {
9090
if (queue.fifo) {
91-
throw new Error('Batching window is not supported for FIFO queues');
91+
throw new ValidationError('Batching window is not supported for FIFO queues', queue);
9292
}
9393
if (!this.props.maxBatchingWindow.isUnresolved() && this.props.maxBatchingWindow.toSeconds() > 300) {
94-
throw new Error(`Maximum batching window must be 300 seconds or less (given ${this.props.maxBatchingWindow.toHumanString()})`);
94+
throw new ValidationError(`Maximum batching window must be 300 seconds or less (given ${this.props.maxBatchingWindow.toHumanString()})`, queue);
9595
}
9696
}
9797
if (this.props.batchSize !== undefined && !Token.isUnresolved(this.props.batchSize)) {
9898
if (this.props.maxBatchingWindow !== undefined && (this.props.batchSize < 1 || this.props.batchSize > 10000)) {
99-
throw new Error(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize}) when batching window is specified.`);
99+
throw new ValidationError(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize}) when batching window is specified.`, queue);
100100
}
101101
if (this.props.maxBatchingWindow === undefined && (this.props.batchSize < 1 || this.props.batchSize > 10)) {
102-
throw new Error(`Maximum batch size must be between 1 and 10 inclusive (given ${this.props.batchSize}) when batching window is not specified.`);
102+
throw new ValidationError(`Maximum batch size must be between 1 and 10 inclusive (given ${this.props.batchSize}) when batching window is not specified.`, queue);
103103
}
104104
}
105105
}
@@ -134,7 +134,7 @@ export class SqsEventSource implements lambda.IEventSource {
134134
*/
135135
public get eventSourceMappingId(): string {
136136
if (!this._eventSourceMappingId) {
137-
throw new Error('SqsEventSource is not yet bound to an event source mapping');
137+
throw new ValidationError('SqsEventSource is not yet bound to an event source mapping', this.queue);
138138
}
139139
return this._eventSourceMappingId;
140140
}
@@ -144,7 +144,7 @@ export class SqsEventSource implements lambda.IEventSource {
144144
*/
145145
public get eventSourceMappingArn(): string {
146146
if (!this._eventSourceMappingArn) {
147-
throw new Error('SqsEventSource is not yet bound to an event source mapping');
147+
throw new ValidationError('SqsEventSource is not yet bound to an event source mapping', this.queue);
148148
}
149149
return this._eventSourceMappingArn;
150150
}

packages/aws-cdk-lib/aws-lambda-event-sources/lib/stream.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { S3OnFailureDestination } from './s3-onfailuire-destination';
22
import { IKey } from '../../aws-kms';
33
import * as lambda from '../../aws-lambda';
4-
import { Duration } from '../../core';
4+
import { Duration, UnscopedValidationError } from '../../core';
55

66
/**
77
* The set of properties for streaming event sources shared by
@@ -178,17 +178,17 @@ export abstract class StreamEventSource implements lambda.IEventSource {
178178
const { minimumPollers, maximumPollers } = props.provisionedPollerConfig;
179179
if (minimumPollers != undefined) {
180180
if (minimumPollers < 1 || minimumPollers > 200) {
181-
throw new Error('Minimum provisioned pollers must be between 1 and 200 inclusive');
181+
throw new UnscopedValidationError('Minimum provisioned pollers must be between 1 and 200 inclusive');
182182
}
183183
}
184184
if (maximumPollers != undefined) {
185185
if (maximumPollers < 1 || maximumPollers > 2000) {
186-
throw new Error('Maximum provisioned pollers must be between 1 and 2000 inclusive');
186+
throw new UnscopedValidationError('Maximum provisioned pollers must be between 1 and 2000 inclusive');
187187
}
188188
}
189189
if (minimumPollers != undefined && maximumPollers != undefined) {
190190
if (minimumPollers > maximumPollers) {
191-
throw new Error('Minimum provisioned pollers must be less than or equal to maximum provisioned pollers');
191+
throw new UnscopedValidationError('Minimum provisioned pollers must be less than or equal to maximum provisioned pollers');
192192
}
193193
}
194194
}
@@ -199,7 +199,7 @@ export abstract class StreamEventSource implements lambda.IEventSource {
199199
protected enrichMappingOptions(options: lambda.EventSourceMappingOptions): lambda.EventSourceMappingOptions {
200200
// check if this event source support S3 as OnFailure, Kinesis, Kafka, DynamoDB has supported S3 OFD
201201
if (this.props.onFailure instanceof S3OnFailureDestination && !options.supportS3OnFailureDestination) {
202-
throw new Error('S3 onFailure Destination is not supported for this event source');
202+
throw new UnscopedValidationError('S3 onFailure Destination is not supported for this event source');
203203
}
204204
return {
205205
...options,

0 commit comments

Comments
 (0)