From 93fd34fae437631385d9e08c35e03337e34f1bed Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Sat, 8 Aug 2026 18:31:55 -0700 Subject: [PATCH] fix(condition): stop shipping all block outputs in every evaluation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ConditionBlockHandler forwarded collectBlockData's full blockData — every block output accumulated so far in the run — to function_execute on each condition evaluation. The resolver already inlines every reference into the expression before the handler runs, so that payload was never read; it only inflated the request body. Inside a wide subflow one flat blockStates map holds every branch's outputs, so a 91-branch parallel pushed the body past the 10MB cap and failed the gate with "Request body size limit exceeded" even though the expression was just a boolean compare. Per-value large-value offload does not catch this: its threshold is 8MB for a single value, while this is an aggregate of many medium ones. Mirrors FunctionBlockHandler, which moved to blockData: {} in #4560 and left the condition handler on the old path. Co-Authored-By: Claude Opus 5 (1M context) --- .../condition/condition-handler.test.ts | 20 ++++++++++++++++++- .../handlers/condition/condition-handler.ts | 10 ++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/sim/executor/handlers/condition/condition-handler.test.ts b/apps/sim/executor/handlers/condition/condition-handler.test.ts index 6a4af6c4096..fa24cec1bfa 100644 --- a/apps/sim/executor/handlers/condition/condition-handler.test.ts +++ b/apps/sim/executor/handlers/condition/condition-handler.test.ts @@ -179,7 +179,7 @@ describe('ConditionBlockHandler', () => { timeout: 5000, envVars: mockContext.environmentVariables, workflowVariables: mockContext.workflowVariables, - blockData: { 'source-block-1': { value: 10, text: 'hello' } }, + blockData: {}, blockNameMapping: { sourceblock: 'source-block-1' }, _context: { workflowId: 'test-workflow-id', @@ -190,6 +190,24 @@ describe('ConditionBlockHandler', () => { ) }) + it('should never forward collected block outputs in the request body', async () => { + mockCollectBlockData.mockReturnValueOnce({ + blockData: { 'huge-block': { payload: 'x'.repeat(1024) } }, + blockNameMapping: { hugeblock: 'huge-block' }, + }) + mockExecuteTool.mockResolvedValueOnce({ success: true, output: { result: true } }) + + const conditions = [ + { id: 'cond1', title: 'if', value: 'true' }, + { id: 'else1', title: 'else', value: '' }, + ] + + await handler.execute(mockContext, mockBlock, { conditions: JSON.stringify(conditions) }) + + const [, toolParams] = mockExecuteTool.mock.calls[0] + expect(toolParams.blockData).toEqual({}) + }) + it('should select the else path if other conditions fail', async () => { mockExecuteTool.mockResolvedValueOnce({ success: true, output: { result: false } }) diff --git a/apps/sim/executor/handlers/condition/condition-handler.ts b/apps/sim/executor/handlers/condition/condition-handler.ts index ec86ac7640c..d21702ae81f 100644 --- a/apps/sim/executor/handlers/condition/condition-handler.ts +++ b/apps/sim/executor/handlers/condition/condition-handler.ts @@ -22,6 +22,12 @@ const CONDITION_TIMEOUT_MS = 5000 * Evaluates a single condition expression. * The resolver preserves legacy Condition expression substitution before this function executes the * resulting JavaScript through the shared function execution boundary. + * + * `blockData` is deliberately empty: the resolver already inlines every `` reference + * into the expression before this runs, so shipping the run's accumulated block outputs would only + * inflate the request body. Sending them blew the 10MB body cap on wide subflows, where a single + * flat `blockStates` map holds every branch's outputs. + * * Returns true if condition is met, false otherwise. */ async function evaluateConditionExpression( @@ -36,7 +42,7 @@ async function evaluateConditionExpression( const contextSetup = `const context = ${JSON.stringify(evalContext)};` const code = `${contextSetup}\nreturn Boolean(${conditionExpression})` - const { blockData, blockNameMapping, blockOutputSchemas } = collectBlockData(ctx, currentNodeId) + const { blockNameMapping, blockOutputSchemas } = collectBlockData(ctx, currentNodeId) const result = await executeTool( 'function_execute', @@ -45,7 +51,7 @@ async function evaluateConditionExpression( timeout: CONDITION_TIMEOUT_MS, envVars: normalizeStringRecord(ctx.environmentVariables), workflowVariables: normalizeWorkflowVariables(ctx.workflowVariables), - blockData, + blockData: {}, blockNameMapping, blockOutputSchemas, _context: {