Skip to content

fix(executor): stop condition/router erroring when downstream blocks are disabled - #6079

Open
waleedlatif1 wants to merge 1 commit into
stagingfrom
worktree-condition-disabled-target
Open

fix(executor): stop condition/router erroring when downstream blocks are disabled#6079
waleedlatif1 wants to merge 1 commit into
stagingfrom
worktree-condition-disabled-target

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Disabling the blocks after a condition made the condition fail with Target block <id> not found. Manual editor runs built the payload from blocks-minus-disabled but sent every edge, so the server got edges pointing at blocks absent from workflow.blocks.
  • Condition and router are the only handlers that resolve their target out of workflow.blocks, so only they threw — every other block type ignores a dangling edge. Hence it looked random.
  • Deployed, scheduled, webhook and run-from-block executions always sent full state, so the editor was the only outlier. The DAG builder already excludes disabled blocks and their edges, so the client-side stripping was both redundant and the cause.
  • Semantics: a branch pointing at a disabled block dead-ends — no error, no passthrough. Manual runs now behave identically to deployed runs.

Changes:

  • use-workflow-execution.ts: keep disabled blocks in the payload so blocks and edges stay consistent; filter to enabled only for trigger resolution, so a disabled trigger still can't be selected.
  • condition-handler.ts: a disabled or missing target dead-ends (selectedPath: null, selectedOption set) instead of throwing. edge-manager already treats that as a routed dead end — a path covered by existing tests, including inside loops and nested conditions.
  • router-handler.ts: exclude disabled/missing targets from the legacy router's candidate list so the model is never offered a route the DAG can't execute. When none remain it dead-ends without calling the model — those runs succeed today (the model picks a disabled block, the DAG dead-ends), so throwing would have failed live deployed workflows.
  • serializer/index.ts: drop connections referencing a block that doesn't exist, so a dangling edge can never reach the executor again.

Router V2 is deliberately untouched: its routes are user-declared ports, so silently removing one from the model's options is a bigger change than for the legacy router, where the target block is the route. It already dead-ends gracefully.

Type of Change

  • Bug fix

Testing

4258 tests pass across executor, serializer, stores, lib/workflows and the editor hooks; typecheck and check:api-validation clean.

New coverage:

  • The client-boundary test was confirmed to fail when the old stripping behavior was temporarily restored, so it genuinely guards the regression.
  • Condition dead-ends for both a disabled and a missing target.
  • Legacy router excludes disabled and missing targets, and dead-ends without a model call when all are disabled.
  • Serializer keeps disabled blocks with their connections, and drops connections to non-existent blocks.

Also verified by hand: a loop whose only inner block is disabled still builds a DAG (the existing "all inner blocks disabled" test has no loop container, so it never reaches the validation it claims to cover), and disabled blocks skip required-field validation so a half-configured disabled block can't fail a run.

Not live-verified in a browser.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…are disabled

Manual editor runs built the executor payload from blocks-minus-disabled but sent
every edge, so the server received edges pointing at blocks absent from
workflow.blocks. Condition and router are the only handlers that resolve their
target out of workflow.blocks, so only they threw "Target block <id> not found";
every other block type ignores a dangling edge. Deployed, scheduled, webhook and
run-from-block executions always sent full state, so the editor was the only
outlier — the DAG builder already excludes disabled blocks and their edges.

- keep disabled blocks in the payload; filter only for trigger resolution
- condition: a disabled or missing target dead-ends the branch instead of throwing
- router: exclude disabled/missing targets from the candidate list, and dead-end
  without calling the model when none remain (previously these runs succeeded
  after picking a disabled block, so throwing would have failed live workflows)
- serializer: drop connections that reference a block that does not exist
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 30, 2026 1:06am

Request Review

@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches core workflow execution paths (editor payload, condition/router handlers, serialization); behavior change is intentional but affects branching and manual runs.

Overview
Fixes editor manual runs failing when a condition or legacy router points at a disabled downstream block. The client had been stripping disabled blocks from the execution payload while still sending all edges, so the server saw dangling edges and handlers threw target block not found.

Editor execution (use-workflow-execution.ts) now keeps disabled blocks in the payload so blocks and edges stay aligned; trigger selection still uses only enabled blocks.

Condition and legacy router handlers treat missing or disabled branch targets as a dead end (selectedPath: null) instead of throwing. The legacy router also drops non-executable targets from LLM candidates and skips the model call when no targets remain.

Serializer drops connections that reference blocks absent from the serialized graph (while still serializing disabled blocks and their edges).

Tests cover the client payload invariant and the new dead-end / filtering behavior.

Reviewed by Cursor Bugbot for commit e1b58c1. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes manual-run condition/router failures when downstream blocks are disabled by keeping blocks and edges consistent and treating non-executable branch targets as dead ends.

  • Client workflow execution payload no longer strips disabled blocks (only trigger resolution uses enabled blocks).
  • Condition handler dead-ends when the selected target is missing or disabled instead of throwing.
  • Legacy router excludes non-executable targets and dead-ends without a model call when none remain.
  • Serializer drops connections whose source/target blocks are not present in the serialized graph.

Confidence Score: 5/5

This PR appears safe to merge; the payload, handler, and serializer changes align with existing DAG dead-end behavior and are covered by targeted tests.

Disabled blocks stay in the client payload so edges remain consistent; condition and legacy router dead-end on non-executable targets instead of throwing; the serializer drops dangling connections; and EdgeManager already treats routed null paths as completion.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts Stops filtering disabled blocks from the execution override; trigger discovery still uses enabled-only state.
apps/sim/executor/handlers/condition/condition-handler.ts Missing/disabled selected targets return a dead-end result with selectedOption set for edge routing.
apps/sim/executor/handlers/router/router-handler.ts Legacy router filters non-executable targets and short-circuits with null route when the candidate list is empty.
apps/sim/serializer/index.ts Connection filter now requires both endpoints to exist in serialized blocks, not only non-dropped custom blocks.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Manual run payload] --> B[Include disabled blocks + all edges]
  B --> C[Serializer]
  C --> D[SerializedWorkflow with enabled flags]
  D --> E[DAG builder drops disabled nodes/edges]
  E --> F{Condition / legacy router}
  F -->|Executable target| G[Activate selected path]
  F -->|Missing or disabled target| H[selectedPath null dead-end]
  H --> I[EdgeManager cascades / completes run]
Loading

Reviews (1): Last reviewed commit: "fix(executor): stop condition/router err..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant