diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md
new file mode 100644
index 0000000000000..6d93dc97a107e
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) > [createTooManyRequestsError](./kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md)
+
+## SavedObjectsErrorHelpers.createTooManyRequestsError() method
+
+Signature:
+
+```typescript
+static createTooManyRequestsError(type: string, id: string): DecoratedError;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| type | string
| |
+| id | string
| |
+
+Returns:
+
+`DecoratedError`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md
new file mode 100644
index 0000000000000..46c94e1756edd
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) > [decorateTooManyRequestsError](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md)
+
+## SavedObjectsErrorHelpers.decorateTooManyRequestsError() method
+
+Signature:
+
+```typescript
+static decorateTooManyRequestsError(error: Error, reason?: string): DecoratedError;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| error | Error
| |
+| reason | string
| |
+
+Returns:
+
+`DecoratedError`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md
new file mode 100644
index 0000000000000..4422966ee3e50
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) > [isTooManyRequestsError](./kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md)
+
+## SavedObjectsErrorHelpers.isTooManyRequestsError() method
+
+Signature:
+
+```typescript
+static isTooManyRequestsError(error: Error | DecoratedError): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| error | Error | DecoratedError
| |
+
+Returns:
+
+`boolean`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md
index 7874be311d52c..a2eff4dd99ea5 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md
@@ -19,6 +19,7 @@ export declare class SavedObjectsErrorHelpers
| [createConflictError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md) | static
| |
| [createGenericNotFoundError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfounderror.md) | static
| |
| [createInvalidVersionError(versionInput)](./kibana-plugin-core-server.savedobjectserrorhelpers.createinvalidversionerror.md) | static
| |
+| [createTooManyRequestsError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md) | static
| |
| [createUnsupportedTypeError(type)](./kibana-plugin-core-server.savedobjectserrorhelpers.createunsupportedtypeerror.md) | static
| |
| [decorateBadRequestError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratebadrequesterror.md) | static
| |
| [decorateConflictError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateconflicterror.md) | static
| |
@@ -28,6 +29,7 @@ export declare class SavedObjectsErrorHelpers
| [decorateGeneralError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorategeneralerror.md) | static
| |
| [decorateNotAuthorizedError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratenotauthorizederror.md) | static
| |
| [decorateRequestEntityTooLargeError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoraterequestentitytoolargeerror.md) | static
| |
+| [decorateTooManyRequestsError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md) | static
| |
| [isBadRequestError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isbadrequesterror.md) | static
| |
| [isConflictError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isconflicterror.md) | static
| |
| [isEsCannotExecuteScriptError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md) | static
| |
@@ -38,4 +40,5 @@ export declare class SavedObjectsErrorHelpers
| [isNotFoundError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isnotfounderror.md) | static
| |
| [isRequestEntityTooLargeError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isrequestentitytoolargeerror.md) | static
| |
| [isSavedObjectsClientError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.issavedobjectsclienterror.md) | static
| |
+| [isTooManyRequestsError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md) | static
| |
diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts
index 623610eebd8d7..3358de1c10311 100644
--- a/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts
+++ b/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts
@@ -73,6 +73,15 @@ describe('savedObjectsClient/decorateEsError', () => {
expect(SavedObjectsErrorHelpers.isConflictError(error)).toBe(true);
});
+ it('makes TooManyRequests a SavedObjectsClient/tooManyRequests error', () => {
+ const error = new esErrors.ResponseError(
+ elasticsearchClientMock.createApiResponse({ statusCode: 429 })
+ );
+ expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(false);
+ expect(decorateEsError(error)).toBe(error);
+ expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(true);
+ });
+
it('makes NotAuthorized a SavedObjectsClient/NotAuthorized error', () => {
const error = new esErrors.ResponseError(
elasticsearchClientMock.createApiResponse({ statusCode: 401 })
diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.ts
index cf8a16cdaae6f..592b268d8219b 100644
--- a/src/core/server/saved_objects/service/lib/decorate_es_error.ts
+++ b/src/core/server/saved_objects/service/lib/decorate_es_error.ts
@@ -28,6 +28,7 @@ const responseErrors = {
isRequestEntityTooLarge: (statusCode: number) => statusCode === 413,
isNotFound: (statusCode: number) => statusCode === 404,
isBadRequest: (statusCode: number) => statusCode === 400,
+ isTooManyRequests: (statusCode: number) => statusCode === 429,
};
const { ConnectionError, NoLivingConnectionsError, TimeoutError } = esErrors;
const SCRIPT_CONTEXT_DISABLED_REGEX = /(?:cannot execute scripts using \[)([a-z]*)(?:\] context)/;
@@ -76,6 +77,10 @@ export function decorateEsError(error: EsErrors) {
return SavedObjectsErrorHelpers.createGenericNotFoundError();
}
+ if (responseErrors.isTooManyRequests(error.statusCode)) {
+ return SavedObjectsErrorHelpers.decorateTooManyRequestsError(error, reason);
+ }
+
if (responseErrors.isBadRequest(error.statusCode)) {
if (
SCRIPT_CONTEXT_DISABLED_REGEX.test(reason || '') ||
diff --git a/src/core/server/saved_objects/service/lib/errors.test.ts b/src/core/server/saved_objects/service/lib/errors.test.ts
index 324d19e279212..931d9f725e412 100644
--- a/src/core/server/saved_objects/service/lib/errors.test.ts
+++ b/src/core/server/saved_objects/service/lib/errors.test.ts
@@ -274,6 +274,53 @@ describe('savedObjectsClient/errorTypes', () => {
});
});
+ describe('TooManyRequests error', () => {
+ describe('decorateTooManyRequestsError', () => {
+ it('returns original object', () => {
+ const error = new Error();
+ expect(SavedObjectsErrorHelpers.decorateTooManyRequestsError(error)).toBe(error);
+ });
+
+ it('makes the error identifiable as a TooManyRequests error', () => {
+ const error = new Error();
+ expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(false);
+ SavedObjectsErrorHelpers.decorateTooManyRequestsError(error);
+ expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(true);
+ });
+
+ it('adds boom properties', () => {
+ const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(new Error());
+ expect(error).toHaveProperty('isBoom', true);
+ });
+
+ describe('error.output', () => {
+ it('defaults to message of error', () => {
+ const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(new Error('foobar'));
+ expect(error.output.payload).toHaveProperty('message', 'foobar');
+ });
+
+ it('prefixes message with passed reason', () => {
+ const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(
+ new Error('foobar'),
+ 'biz'
+ );
+ expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
+ });
+
+ it('sets statusCode to 429', () => {
+ const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(new Error('foo'));
+ expect(error.output).toHaveProperty('statusCode', 429);
+ });
+
+ it('preserves boom properties of input', () => {
+ const error = Boom.tooManyRequests();
+ SavedObjectsErrorHelpers.decorateTooManyRequestsError(error);
+ expect(error.output).toHaveProperty('statusCode', 429);
+ });
+ });
+ });
+ });
+
describe('EsCannotExecuteScript error', () => {
describe('decorateEsCannotExecuteScriptError', () => {
it('returns original object', () => {
diff --git a/src/core/server/saved_objects/service/lib/errors.ts b/src/core/server/saved_objects/service/lib/errors.ts
index 9614d692741e0..6fd5bc9de0ec5 100644
--- a/src/core/server/saved_objects/service/lib/errors.ts
+++ b/src/core/server/saved_objects/service/lib/errors.ts
@@ -33,6 +33,8 @@ const CODE_REQUEST_ENTITY_TOO_LARGE = 'SavedObjectsClient/requestEntityTooLarge'
const CODE_NOT_FOUND = 'SavedObjectsClient/notFound';
// 409 - Conflict
const CODE_CONFLICT = 'SavedObjectsClient/conflict';
+// 429 - Too Many Requests
+const CODE_TOO_MANY_REQUESTS = 'SavedObjectsClient/tooManyRequests';
// 400 - Es Cannot Execute Script
const CODE_ES_CANNOT_EXECUTE_SCRIPT = 'SavedObjectsClient/esCannotExecuteScript';
// 503 - Es Unavailable
@@ -162,6 +164,18 @@ export class SavedObjectsErrorHelpers {
return isSavedObjectsClientError(error) && error[code] === CODE_CONFLICT;
}
+ public static decorateTooManyRequestsError(error: Error, reason?: string) {
+ return decorate(error, CODE_TOO_MANY_REQUESTS, 429, reason);
+ }
+
+ public static createTooManyRequestsError(type: string, id: string) {
+ return SavedObjectsErrorHelpers.decorateTooManyRequestsError(Boom.tooManyRequests());
+ }
+
+ public static isTooManyRequestsError(error: Error | DecoratedError) {
+ return isSavedObjectsClientError(error) && error[code] === CODE_TOO_MANY_REQUESTS;
+ }
+
public static decorateEsCannotExecuteScriptError(error: Error, reason?: string) {
return decorate(error, CODE_ES_CANNOT_EXECUTE_SCRIPT, 400, reason);
}
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index 772be68f507d5..afc71d39d4a62 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -2220,6 +2220,8 @@ export class SavedObjectsErrorHelpers {
// (undocumented)
static createInvalidVersionError(versionInput?: string): DecoratedError;
// (undocumented)
+ static createTooManyRequestsError(type: string, id: string): DecoratedError;
+ // (undocumented)
static createUnsupportedTypeError(type: string): DecoratedError;
// (undocumented)
static decorateBadRequestError(error: Error, reason?: string): DecoratedError;
@@ -2238,6 +2240,8 @@ export class SavedObjectsErrorHelpers {
// (undocumented)
static decorateRequestEntityTooLargeError(error: Error, reason?: string): DecoratedError;
// (undocumented)
+ static decorateTooManyRequestsError(error: Error, reason?: string): DecoratedError;
+ // (undocumented)
static isBadRequestError(error: Error | DecoratedError): boolean;
// (undocumented)
static isConflictError(error: Error | DecoratedError): boolean;
@@ -2259,6 +2263,8 @@ export class SavedObjectsErrorHelpers {
//
// (undocumented)
static isSavedObjectsClientError(error: any): error is DecoratedError;
+ // (undocumented)
+ static isTooManyRequestsError(error: Error | DecoratedError): boolean;
}
// @public