# How Condition Handlers Evaluate Workflow Branching Logic in SimStudio AI

> Learn how SimStudio AI condition handlers evaluate workflow branching logic. Discover their process of parsing JSON, executing JavaScript, and routing based on boolean results.

- Repository: [Sim/sim](https://github.com/simstudioai/sim)
- Tags: internals
- Published: 2026-05-02

---

**Condition handlers in SimStudio AI evaluate workflow branching logic by parsing JSON condition definitions, executing sandboxed JavaScript expressions via the `function_execute` tool with a 5-second timeout, and routing execution to the first matching path based on boolean results.**

The condition block serves as the decision-making core of SimStudio AI workflows. According to the simstudioai/sim source code, the condition handler ([`apps/sim/executor/handlers/condition/condition-handler.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/executor/handlers/condition/condition-handler.ts)) transforms declarative user input into isolated code evaluations that determine execution flow. This process involves context aggregation, secure script execution, and precise edge resolution to route data between workflow blocks.

## Parsing User-Defined Conditions

The evaluation process begins with `ConditionBlockHandler.parseConditions`, which normalizes raw input into a structured array of condition objects.

This method accepts either a JSON string or an already-parsed array and validates each entry against the `{ id, title, value }` interface. If the input contains malformed data, the handler surfaces a clear log message and throws an exception, halting workflow execution before any evaluation occurs.

The parsed conditions represent the decision branches—each containing a unique identifier, human-readable title, and the JavaScript expression that determines if that path should be taken.

## Building the Evaluation Context

Before expressions can execute, the handler must establish what variables the code can reference. The `ConditionBlockHandler.buildEvaluationContext` method merges the output from the source block (the block feeding into the condition) into a plain JavaScript object.

This context object becomes the variable scope for condition expressions. When users write expressions like `<ticket.priority> === 'high'`, the angle-bracket notation resolves against this context, allowing conditions to reference upstream data without direct database access or unsafe scope leakage.

## Executing Sandboxed Condition Expressions

For each condition, the handler calls `evaluateConditionExpression`, which wraps the user code in a safety harness:

```ts
const context = { …evalContext };
return Boolean(<condition>);

```

The actual execution occurs inside the **function_execute** tool, invoked via `executeTool('function_execute', …)`. This approach provides critical isolation:

- **Timeout protection**: Execution halts after `CONDITION_TIMEOUT_MS` (5 seconds)
- **Variable isolation**: Only the built context and workflow/environment variables are accessible
- **Result normalization**: The tool returns `{ success, output?.result }`, which the handler coerces to a boolean

If the tool reports failure or throws an error, the handler logs the specific failure and aborts the entire workflow, preventing partial execution of invalid branches.

## Routing to the Next Block

Once expressions are evaluated, `ConditionBlockHandler.evaluateConditions` determines the execution path. The algorithm follows strict precedence rules:

1. **Else handling**: If a condition title matches the special *else* title, its edge is selected immediately when no prior condition matches
2. **First-match-wins**: For standard conditions, the handler iterates sequentially and selects the first condition returning `true`
3. **Edge resolution**: The handler calls `findConnectionForCondition` to locate the outgoing connection whose `sourceHandle` matches `condition-{conditionId}` (handled via utilities in [`apps/sim/lib/workflows/condition-ids.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/lib/workflows/condition-ids.ts))

When a match is found, the handler returns the target block's ID, type, and title. If no conditions match and no else clause exists, `selectedPath` returns `null`, effectively terminating that branch of the workflow.

## Recording Decisions and Returning Output

The handler maintains audit trails by storing the selected condition ID in `ctx.decisions.condition` under a key derived from either the virtual or physical block ID. This storage enables downstream blocks to reference which branch was taken using the `<condition.selectedOption>` syntax.

The final output merges the source block's data (with internal metadata stripped) alongside condition-specific fields:

```ts
{
  conditionResult: true,
  selectedPath: { blockId, blockType, blockTitle },
  selectedOption: condition.id,
}

```

When no match occurs, `conditionResult` is `false` and both `selectedPath` and `selectedOption` are `null`, signaling to subsequent blocks that no branching condition was satisfied.

## Practical Implementation Example

Define a condition block in your workflow JSON:

```json
{
  "id": "block-3",
  "metadata": { "id": "condition" },
  "inputs": {
    "conditions": [
      { "id": "c1", "title": "High priority", "value": "<ticket.priority> === 'high'" },
      { "id": "c2", "title": "Urgent keyword", "value": "<ticket.subject>.toLowerCase().includes('urgent')" },
      { "id": "c3", "title": "Else", "value": "true" }
    ]
  }
}

```

Configure the corresponding connections to route execution:

```json
[
  { "source": "block-2", "target": "block-3", "sourceHandle": "output" },
  { "source": "block-3", "target": "block-4", "sourceHandle": "condition-c1" },
  { "source": "block-3", "target": "block-5", "sourceHandle": "condition-c2" },
  { "source": "block-3", "target": "block-6", "sourceHandle": "condition-c3" }
]

```

Within the executor, the handler selects the appropriate edge:

```ts
const { selectedConnection, selectedCondition } = await handler.evaluateConditions(
  conditions,
  outgoingConnections,
  evalContext,
  ctx,
  block.id
);
// selectedConnection.target now references block-4, block-5, or block-6

```

## Summary

- **Condition parsing** converts raw JSON into validated `{ id, title, value }` objects via `parseConditions`
- **Context building** aggregates source block output into a sandboxed variable scope using `buildEvaluationContext`
- **Sandboxed execution** runs JavaScript expressions through the `function_execute` tool with a 5-second timeout and boolean coercion
- **Branch selection** follows first-match-wins logic, with special handling for else clauses and precise edge mapping via `condition-{id}` handles
- **Audit trails** store decisions in `ctx.decisions.condition`, enabling downstream reference via `selectedOption`
- **Type-safe outputs** return `conditionResult`, `selectedPath`, and `selectedOption` to inform subsequent workflow steps

## Frequently Asked Questions

### How does the condition handler isolate JavaScript execution?

The handler delegates expression evaluation to the `function_execute` tool, which executes code in a sandboxed environment with restricted variable access and a hard 5-second timeout (`CONDITION_TIMEOUT_MS`). This prevents user-defined conditions from accessing unauthorized system resources or entering infinite loops.

### What happens if no conditions evaluate to true?

If no standard conditions match and no else clause is defined, `evaluateConditions` returns `conditionResult: false` with `selectedPath` and `selectedOption` set to `null`. The workflow execution halts for that branch unless subsequent blocks handle null paths explicitly.

### How does SimStudio AI handle edge cases when duplicating condition blocks?

The [`apps/sim/lib/workflows/condition-ids.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/lib/workflows/condition-ids.ts) utility ensures that when blocks are duplicated, condition IDs and edge handles (`condition-{conditionId}`) are remapped consistently. This prevents routing conflicts and ensures the handler in [`condition-handler.ts`](https://github.com/simstudioai/sim/blob/main/condition-handler.ts) resolves the correct `sourceHandle` even in copied workflows.

### Can condition expressions access data from multiple previous blocks?

Yes. The `buildEvaluationContext` method aggregates output from the immediate source block, but the context can be extended to include workflow-wide variables and environment data. However, expressions can only reference data explicitly included in the evaluation context passed to `evaluateConditionExpression`.