From 6a047b47587b96e84cbcb18f8d389548efdc8a65 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 5 Jul 2026 02:21:02 +1000 Subject: [PATCH] fix: Server crash from unhandled promise rejection when multiple Cloud Code validator fields fail --- spec/CloudCode.Validator.spec.js | 21 +++++++++++++++++++++ src/triggers.js | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spec/CloudCode.Validator.spec.js b/spec/CloudCode.Validator.spec.js index 11ccc82766..0ae07db164 100644 --- a/spec/CloudCode.Validator.spec.js +++ b/spec/CloudCode.Validator.spec.js @@ -504,6 +504,27 @@ describe('cloud validator', () => { }); }); + it('does not leave an unhandled rejection when multiple fields fail validation (#8826)', async () => { + const rejections = []; + const onUnhandledRejection = reason => rejections.push(reason); + process.on('unhandledRejection', onUnhandledRejection); + try { + Parse.Cloud.define('hello', () => 'Hello world!', { + fields: { + type: { type: String, options: ['Option A', 'Option B'] }, + project: { required: true }, + }, + }); + await expectAsync(Parse.Cloud.run('hello', { type: 'Invalid' })).toBeRejectedWith( + jasmine.objectContaining({ code: Parse.Error.VALIDATION_ERROR }) + ); + await new Promise(resolve => setTimeout(resolve, 100)); + expect(rejections).toEqual([]); + } finally { + process.removeListener('unhandledRejection', onUnhandledRejection); + } + }); + it('set params options function', done => { Parse.Cloud.define( 'hello', diff --git a/src/triggers.js b/src/triggers.js index f66d96f942..f05cf4dfcf 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -815,7 +815,7 @@ async function builtInTriggerValidator(options, request, auth) { requiredParam(key); } } else { - const optionPromises = []; + const optionValidations = []; for (const key in options.fields) { const opt = options.fields[key]; let val = params[key]; @@ -850,12 +850,12 @@ async function builtInTriggerValidator(options, request, auth) { } } if (opt.options) { - optionPromises.push(validateOptions(opt, key, val)); + optionValidations.push([opt, key, val]); } } } } - await Promise.all(optionPromises); + await Promise.all(optionValidations.map(([o, k, v]) => validateOptions(o, k, v))); } let userRoles = options.requireAnyUserRoles; let requireAllRoles = options.requireAllUserRoles;