From 86f47ee6dc88397b05bfb784b0092674ba3b4289 Mon Sep 17 00:00:00 2001 From: mfsiega <93014743+mfsiega@users.noreply.github.com> Date: Fri, 1 May 2026 12:34:37 +0200 Subject: [PATCH] fix(Schedule Node): Cap day-of-month jitter at 28 (#29614) Co-authored-by: Claude Opus 4.7 (1M context) --- packages/nodes-base/nodes/Schedule/GenericFunctions.ts | 4 +++- .../nodes-base/nodes/Schedule/test/GenericFunctions.test.ts | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/nodes-base/nodes/Schedule/GenericFunctions.ts b/packages/nodes-base/nodes/Schedule/GenericFunctions.ts index e312186b1e9..84e55a9e393 100644 --- a/packages/nodes-base/nodes/Schedule/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Schedule/GenericFunctions.ts @@ -126,7 +126,9 @@ export const toCronExpression = (interval: ScheduleInterval, nodeKey: string): C return `${second} ${minute} ${hour} * * ${daysOfWeek}` as CronExpression; } - const dayOfMonth = interval.triggerAtDayOfMonth ?? stableInt(nodeKey, 'dayOfMonth', 1, 31); + // Cap at 29 (exclusive) so jitter yields 1-28: any higher day would silently + // skip months that don't contain it (e.g. day 30 skips February every year). + const dayOfMonth = interval.triggerAtDayOfMonth ?? stableInt(nodeKey, 'dayOfMonth', 1, 29); return `${second} ${minute} ${hour} ${dayOfMonth} */${interval.monthsInterval} *`; }; diff --git a/packages/nodes-base/nodes/Schedule/test/GenericFunctions.test.ts b/packages/nodes-base/nodes/Schedule/test/GenericFunctions.test.ts index 77d8cee86ec..d9a75e51761 100644 --- a/packages/nodes-base/nodes/Schedule/test/GenericFunctions.test.ts +++ b/packages/nodes-base/nodes/Schedule/test/GenericFunctions.test.ts @@ -33,7 +33,7 @@ function mockMomentTz(values: { // from the input interval. // // For `seed = 'test-key'`, `stableInt` produces: -// second=56, minute=19, hour=14, dayOfMonth=4 +// second=56, minute=19, hour=14, dayOfMonth=22 const TEST_SEED = 'test-key'; describe('toCronExpression', () => { @@ -158,7 +158,7 @@ describe('toCronExpression', () => { TEST_SEED, ); expect(result).toEqual('56 0 0 1 */3 *'); - // Nothing pinned, so sec=56 / min=19 / hr=14 / dom=4 are all filler. + // Nothing pinned, so sec=56 / min=19 / hr=14 / dom=22 are all filler. const result1 = toCronExpression( { field: 'months', @@ -166,7 +166,7 @@ describe('toCronExpression', () => { }, TEST_SEED, ); - expect(result1).toEqual('56 19 14 4 */3 *'); + expect(result1).toEqual('56 19 14 22 */3 *'); }); });