diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index 1e34383832..b0f82b326c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -682,10 +682,10 @@ export function useWorkflowExecution() { const workflowEdges = (executionWorkflowState?.edges ?? latestWorkflowState.edges) as typeof currentWorkflow.edges - // Filter out blocks without type (these are layout-only blocks) + // Filter out blocks without type (these are layout-only blocks) and disabled blocks const validBlocks = Object.entries(workflowBlocks).reduce( (acc, [blockId, block]) => { - if (block?.type) { + if (block?.type && block.enabled !== false) { acc[blockId] = block } return acc @@ -725,13 +725,18 @@ export function useWorkflowExecution() { } }) - // Do not filter out trigger blocks; executor may need to start from them + // Filter out blocks without type and disabled blocks const filteredStates = Object.entries(mergedStates).reduce( (acc, [id, block]) => { if (!block || !block.type) { logger.warn(`Skipping block with undefined type: ${id}`, block) return acc } + // Skip disabled blocks to prevent them from being passed to executor + if (block.enabled === false) { + logger.warn(`Skipping disabled block: ${id}`) + return acc + } acc[id] = block return acc }, diff --git a/apps/sim/executor/dag/construction/paths.ts b/apps/sim/executor/dag/construction/paths.ts index 55cf559d3c..ec7ea48836 100644 --- a/apps/sim/executor/dag/construction/paths.ts +++ b/apps/sim/executor/dag/construction/paths.ts @@ -28,6 +28,24 @@ export class PathConstructor { const block = workflow.blocks.find((b) => b.id === triggerBlockId) if (block) { + if (!block.enabled) { + logger.error('Provided triggerBlockId is disabled, finding alternative', { + triggerBlockId, + blockEnabled: block.enabled, + }) + // Try to find an alternative enabled trigger instead of failing + const alternativeTrigger = this.findExplicitTrigger(workflow) + if (alternativeTrigger) { + logger.info('Using alternative enabled trigger', { + disabledTriggerId: triggerBlockId, + alternativeTriggerId: alternativeTrigger, + }) + return alternativeTrigger + } + throw new Error( + `Trigger block ${triggerBlockId} is disabled and no alternative enabled trigger found` + ) + } return triggerBlockId } @@ -95,8 +113,13 @@ export class PathConstructor { private buildAdjacencyMap(workflow: SerializedWorkflow): Map { const adjacency = new Map() + const enabledBlocks = new Set(workflow.blocks.filter((b) => b.enabled).map((b) => b.id)) for (const connection of workflow.connections) { + if (!enabledBlocks.has(connection.source) || !enabledBlocks.has(connection.target)) { + continue + } + const neighbors = adjacency.get(connection.source) ?? [] neighbors.push(connection.target) adjacency.set(connection.source, neighbors) diff --git a/apps/sim/lib/workflows/executor/execution-core.ts b/apps/sim/lib/workflows/executor/execution-core.ts index 08b5b60f6e..6da2316490 100644 --- a/apps/sim/lib/workflows/executor/execution-core.ts +++ b/apps/sim/lib/workflows/executor/execution-core.ts @@ -257,12 +257,7 @@ export async function executeWorkflowCore( const startBlock = TriggerUtils.findStartBlock(mergedStates, executionKind, false) if (!startBlock) { - const errorMsg = - executionKind === 'api' - ? 'No API trigger block found. Add an API Trigger block to this workflow.' - : executionKind === 'chat' - ? 'No chat trigger block found. Add a Chat Trigger block to this workflow.' - : 'No trigger block found for this workflow.' + const errorMsg = 'No start block found. Add a start block to this workflow.' logger.error(`[${requestId}] ${errorMsg}`) throw new Error(errorMsg) } diff --git a/apps/sim/lib/workflows/triggers.ts b/apps/sim/lib/workflows/triggers.ts index e502671774..dfb5601d2c 100644 --- a/apps/sim/lib/workflows/triggers.ts +++ b/apps/sim/lib/workflows/triggers.ts @@ -177,6 +177,11 @@ export function resolveStartCandidates( const candidates: StartBlockCandidate[] = [] for (const [blockId, block] of entries) { + // Skip disabled blocks - they cannot be used as triggers + if ('enabled' in block && block.enabled === false) { + continue + } + const path = classifyStartBlock(block) if (!path) continue