Skip to content

Commit 091df2a

Browse files
fix: map Lambda exceptions correctly (#4804)
fix: correctly map lambda exceptions
1 parent 67612bd commit 091df2a

File tree

3 files changed

+143
-74
lines changed

3 files changed

+143
-74
lines changed

packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_exception.dart

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,27 @@ sealed class CognitoServiceException extends core.AuthServiceException {
2727
/// {@endtemplate}
2828
final class LambdaException extends CognitoServiceException {
2929
/// {@macro amplify_auth_cognito_dart.sdk.lambda_exception}
30-
factory LambdaException(
31-
String message, {
32-
String? recoverySuggestion,
33-
Object? underlyingException,
34-
}) {
35-
final match = _errorRegex.firstMatch(message);
36-
final lambdaName = match?.group(1);
37-
final parsedMessage = match?.group(2);
38-
if (parsedMessage != null) {
39-
message = parsedMessage;
40-
}
41-
return LambdaException._(
42-
message,
43-
lambdaName: lambdaName,
44-
recoverySuggestion: recoverySuggestion,
45-
underlyingException: underlyingException,
46-
);
47-
}
48-
49-
const LambdaException._(
30+
const LambdaException(
5031
super.message, {
51-
this.lambdaName,
5232
super.recoverySuggestion,
5333
super.underlyingException,
54-
});
34+
}) : _message = message;
35+
36+
final String _message;
37+
38+
@override
39+
String get message {
40+
final match = _errorRegex.firstMatch(_message);
41+
final parsedMessage = match?.group(2);
42+
return parsedMessage ?? _message;
43+
}
44+
45+
/// The name of the lambda which triggered this exception.
46+
String? get lambdaName {
47+
final match = _errorRegex.firstMatch(_message);
48+
final lambdaName = match?.group(1);
49+
return lambdaName;
50+
}
5551

5652
/// Whether [exception] originated in a user Lambda.
5753
static bool isLambdaException(String exception) =>
@@ -65,9 +61,6 @@ final class LambdaException extends CognitoServiceException {
6561
/// errors.
6662
static final RegExp _errorRegex = RegExp(r'(\w+) failed with error (.*)\.');
6763

68-
/// The name of the lambda which triggered this exception.
69-
final String? lambdaName;
70-
7164
@override
7265
String get runtimeTypeName => 'LambdaException';
7366
}
@@ -227,7 +220,7 @@ final class InvalidEmailRoleAccessPolicyException
227220
/// {@template amplify_auth_cognito_dart.sdk_exception.invalid_lambda_response_exception}
228221
/// This exception is thrown when Amazon Cognito encounters an invalid Lambda response.
229222
/// {@endtemplate}
230-
final class InvalidLambdaResponseException extends CognitoServiceException {
223+
final class InvalidLambdaResponseException extends LambdaException {
231224
/// {@macro amplify_auth_cognito_dart.sdk_exception.invalid_lambda_response_exception}
232225
const InvalidLambdaResponseException(
233226
super.message, {
@@ -456,7 +449,7 @@ final class UnauthorizedException extends CognitoServiceException {
456449
/// {@template amplify_auth_cognito_dart.sdk_exception.unexpected_lambda_exception}
457450
/// This exception is thrown when Amazon Cognito encounters an unexpected exception with Lambda.
458451
/// {@endtemplate}
459-
final class UnexpectedLambdaException extends CognitoServiceException {
452+
final class UnexpectedLambdaException extends LambdaException {
460453
/// {@macro amplify_auth_cognito_dart.sdk_exception.unexpected_lambda_exception}
461454
const UnexpectedLambdaException(
462455
super.message, {
@@ -501,7 +494,7 @@ final class UnsupportedTokenTypeException extends CognitoServiceException {
501494
/// {@template amplify_auth_cognito_dart.sdk_exception.user_lambda_validation_exception}
502495
/// This exception is thrown when the Amazon Cognito service encounters a user validation exception with the Lambda service.
503496
/// {@endtemplate}
504-
final class UserLambdaValidationException extends CognitoServiceException {
497+
final class UserLambdaValidationException extends LambdaException {
505498
/// {@macro amplify_auth_cognito_dart.sdk_exception.user_lambda_validation_exception}
506499
const UserLambdaValidationException(
507500
super.message, {
@@ -615,15 +608,6 @@ Object transformSdkException(Object e) {
615608
final message = e.message ?? 'An unknown error occurred';
616609
final shapeName = e.shapeId?.shape;
617610

618-
// Some exceptions are returned as non-Lambda exceptions even though they
619-
// orginated in user-defined lambdas.
620-
if (LambdaException.isLambdaException(message) ||
621-
shapeName == 'InvalidLambdaResponseException' ||
622-
shapeName == 'UnexpectedLambdaException' ||
623-
shapeName == 'UserLambdaValidationException') {
624-
return LambdaException(message, underlyingException: e);
625-
}
626-
627611
return switch (shapeName) {
628612
'AliasExistsException' => AliasExistsException(
629613
message,
@@ -766,6 +750,13 @@ Object transformSdkException(Object e) {
766750
message,
767751
underlyingException: e,
768752
),
769-
_ => UnknownServiceException(message, underlyingException: e),
753+
_ => (() {
754+
// Some exceptions are returned as non-Lambda exceptions even though they
755+
// originated in user-defined lambdas.
756+
if (LambdaException.isLambdaException(message)) {
757+
return LambdaException(message, underlyingException: e);
758+
}
759+
return UnknownServiceException(message, underlyingException: e);
760+
})(),
770761
};
771762
}

packages/auth/amplify_auth_cognito_dart/test/sdk/sdk_exception_test.dart

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,17 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import 'package:amplify_auth_cognito_dart/src/sdk/sdk_exception.dart';
5+
import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/user_lambda_validation_exception.dart'
6+
as cognito;
57
import 'package:amplify_core/amplify_core.dart';
8+
import 'package:smithy/smithy.dart';
69
import 'package:test/test.dart';
710

11+
const lambdaName = 'Foo';
12+
const lambdaMessage = 'Something went wrong';
13+
// errors that originate from lambdas are in the format "<Lambda Name> failed with error <Error>."
14+
const lambdaErrorMessage = '$lambdaName failed with error $lambdaMessage.';
15+
816
void main() {
917
group('SDK exception', () {
1018
group('LambdaException', () {
@@ -14,7 +22,7 @@ void main() {
1422
test('matches string', () {
1523
expect(LambdaException.isLambdaException(message), isTrue);
1624

17-
final exception = LambdaException(message);
25+
const exception = LambdaException(message);
1826
expect(exception.message, error);
1927
expect(exception.lambdaName, 'PreConfirmation');
2028
});
@@ -29,6 +37,58 @@ void main() {
2937
});
3038
});
3139

40+
group('transformSdkException', () {
41+
test('maps SDK Lambda exceptions to the Amplify equivalent', () {
42+
final exception = cognito.UserLambdaValidationException(
43+
message: lambdaErrorMessage,
44+
);
45+
final transformed = transformSdkException(exception);
46+
expect(
47+
transformed,
48+
// UserLambdaValidationException from the SDK should be mapped to
49+
// UserLambdaValidationException from Amplify
50+
isA<UserLambdaValidationException>()
51+
.having(
52+
(e) => e.lambdaName,
53+
'lambdaName',
54+
lambdaName,
55+
)
56+
.having(
57+
(e) => e.message,
58+
'message',
59+
lambdaMessage,
60+
),
61+
);
62+
});
63+
64+
test('maps all other Lambda exceptions to a generic LambdaException', () {
65+
const exception = UnhandledException(lambdaErrorMessage);
66+
final transformed = transformSdkException(exception);
67+
expect(
68+
transformed,
69+
isA<LambdaException>()
70+
.having(
71+
(e) => e.lambdaName,
72+
'lambdaName',
73+
lambdaName,
74+
)
75+
.having(
76+
(e) => e.message,
77+
'message',
78+
lambdaMessage,
79+
),
80+
);
81+
});
82+
83+
test('maps to UnknownServiceException by default', () {
84+
const exception = UnhandledException('error');
85+
expect(
86+
transformSdkException(exception),
87+
isA<UnknownServiceException>(),
88+
);
89+
});
90+
});
91+
3292
test('transforms network exceptions', () {
3393
final networkException = AWSHttpException(
3494
AWSHttpRequest.get(Uri.parse('https://example.com')),
@@ -40,3 +100,24 @@ void main() {
40100
});
41101
});
42102
}
103+
104+
class UnhandledException implements SmithyException {
105+
const UnhandledException(this._message);
106+
107+
final String _message;
108+
109+
@override
110+
String? get message => _message;
111+
112+
@override
113+
RetryConfig? get retryConfig => null;
114+
115+
@override
116+
ShapeId? get shapeId => const ShapeId(
117+
shape: 'UnhandledException',
118+
namespace: '',
119+
);
120+
121+
@override
122+
Exception? get underlyingException => null;
123+
}

packages/auth/amplify_auth_cognito_dart/tool/generate_sdk_exceptions.dart

100644100755
Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -59,30 +59,27 @@ sealed class CognitoServiceException extends core.AuthServiceException {
5959
/// {@endtemplate}
6060
final class LambdaException extends CognitoServiceException {
6161
/// {@macro amplify_auth_cognito_dart.sdk.lambda_exception}
62-
factory LambdaException(String message, {
63-
String? recoverySuggestion,
64-
Object? underlyingException,
65-
}) {
66-
final match = _errorRegex.firstMatch(message);
67-
final lambdaName = match?.group(1);
68-
final parsedMessage = match?.group(2);
69-
if (parsedMessage != null) {
70-
message = parsedMessage;
71-
}
72-
return LambdaException._(
73-
message,
74-
lambdaName: lambdaName,
75-
recoverySuggestion: recoverySuggestion,
76-
underlyingException: underlyingException,
77-
);
78-
}
79-
80-
const LambdaException._(
62+
const LambdaException(
8163
super.message, {
82-
this.lambdaName,
8364
super.recoverySuggestion,
8465
super.underlyingException,
85-
});
66+
}) : _message = message;
67+
68+
final String _message;
69+
70+
@override
71+
String get message {
72+
final match = _errorRegex.firstMatch(_message);
73+
final parsedMessage = match?.group(2);
74+
return parsedMessage ?? _message;
75+
}
76+
77+
/// The name of the lambda which triggered this exception.
78+
String? get lambdaName {
79+
final match = _errorRegex.firstMatch(_message);
80+
final lambdaName = match?.group(1);
81+
return lambdaName;
82+
}
8683
8784
/// Whether [exception] originated in a user Lambda.
8885
static bool isLambdaException(String exception) =>
@@ -96,9 +93,6 @@ final class LambdaException extends CognitoServiceException {
9693
/// errors.
9794
static final RegExp _errorRegex = RegExp(r'(\w+) failed with error (.*)\.');
9895
99-
/// The name of the lambda which triggered this exception.
100-
final String? lambdaName;
101-
10296
@override
10397
String get runtimeTypeName => 'LambdaException';
10498
}
@@ -143,14 +137,19 @@ final class UnknownServiceException extends CognitoServiceException
143137

144138
final hasCoreType = authExceptions.keys.contains(shapeName);
145139
final className = authExceptions[shapeName] ?? shapeName.pascalCase;
140+
final isLambdaException = [
141+
'InvalidLambdaResponseException',
142+
'UnexpectedLambdaException',
143+
'UserLambdaValidationException',
144+
].contains(shapeName);
146145
final templateName =
147146
'amplify_auth_cognito_dart.sdk_exception.${shapeName.snakeCase}';
148147
final docs = shape.formattedDocs(context);
149148
exceptions.writeln('''
150149
/// {@template $templateName}
151150
${docs.isEmpty ? '/// Cognito `$shapeName` exception' : docs}
152151
/// {@endtemplate}
153-
final class $className extends CognitoServiceException ${hasCoreType ? 'implements core.Auth$shapeName' : ''} {
152+
final class $className extends ${isLambdaException ? 'LambdaException' : 'CognitoServiceException'} ${hasCoreType ? 'implements core.Auth$shapeName' : ''} {
154153
/// {@macro $templateName}
155154
const $className(
156155
super.message, {
@@ -176,15 +175,6 @@ Object transformSdkException(Object e) {
176175
final message = e.message ?? 'An unknown error occurred';
177176
final shapeName = e.shapeId?.shape;
178177
179-
// Some exceptions are returned as non-Lambda exceptions even though they
180-
// orginated in user-defined lambdas.
181-
if (LambdaException.isLambdaException(message) ||
182-
shapeName == 'InvalidLambdaResponseException' ||
183-
shapeName == 'UnexpectedLambdaException' ||
184-
shapeName == 'UserLambdaValidationException') {
185-
return LambdaException(message, underlyingException: e);
186-
}
187-
188178
return switch (shapeName) {
189179
''');
190180

@@ -196,7 +186,14 @@ Object transformSdkException(Object e) {
196186
}
197187

198188
exceptions.write('''
199-
_ => UnknownServiceException(message, underlyingException: e),
189+
_ => (() {
190+
// Some exceptions are returned as non-Lambda exceptions even though they
191+
// originated in user-defined lambdas.
192+
if (LambdaException.isLambdaException(message)) {
193+
return LambdaException(message, underlyingException: e);
194+
}
195+
return UnknownServiceException(message, underlyingException: e);
196+
})(),
200197
};
201198
}
202199
''');

0 commit comments

Comments
 (0)