﻿---
title: Troubleshoot workflows
description: Resolve common issues with Elastic Workflows. Trigger attachment, flow control, case and alert steps, Liquid filters, AI connector IDs, composition, human-in-the-loop, and concurrency.
url: https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/authoring-techniques/troubleshooting
products:
  - Elastic Cloud Enterprise
  - Elastic Cloud Hosted
  - Elastic Cloud Serverless
  - Elastic Cloud on Kubernetes
  - Elastic Stack
  - Kibana
applies_to:
  - Elastic Cloud Serverless: Generally available
  - Elastic Stack: Generally available since 9.4
---

# Troubleshoot workflows
Quick answers to the issues first-time workflow authors hit most often. Each section states the symptom, the cause, and the resolution.

## Triggers


### An alert workflow never fires

**Symptom.** You've authored a workflow with `type: alert` and enabled it, but the workflow never runs when the expected alerts fire.
**Cause.** Declaring the trigger is necessary but not sufficient. The workflow must also be attached to the alerting or detection rule's **Actions** with a **Run Workflow** action. Without the attachment, alerts fire from the rule but the workflow is never invoked.
**Resolution.** Open the rule, add a **Run Workflow** action, and select the workflow. Refer to [Alert triggers](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/triggers/alert-triggers) for the full setup sequence.

### A scheduled workflow stopped firing

**Symptom.** A previously working scheduled workflow stops executing.
**Cause.** One of three common causes:
1. The workflow was disabled (`enabled: false`).
2. The interval is shorter than 1 minute. 9.4 enforces a minimum of `1m` / `60s`. Pre-9.4 schedules with shorter intervals were auto-migrated on first edit.
3. A `drop` concurrency strategy is skipping new runs while a prior run is still executing.

**Resolution.** Verify the workflow is enabled, check the interval in the YAML editor, and review execution history for `skipped` entries. For concurrency details, refer to [Settings concurrency control](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/authoring-techniques/pass-data-handle-errors).

### A `workflows.failed` trigger rejects `condition` at the top level

**Symptom.** The workflow editor rejects a `workflows.failed` trigger when `condition` is placed directly under the trigger.
**Cause.** The condition belongs under an `on:` block, not at the trigger top level.
**Resolution.** Nest the condition under `on:`:
```yaml
triggers:
  - type: workflows.failed
    on:
      condition: "event.workflow.name : 'ops--rollback-deployment'"
```

Refer to [Event-driven triggers](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/triggers/event-driven-triggers).

## Flow control


### A `while` loop stopped silently after 2000 iterations

**Symptom.** A `while` loop exits without an error after exactly 2000 iterations, even though the work isn't done.
**Cause.** `max-iterations` defaults to 2000, and the default `on-limit` is `continue` — so the step **succeeds quietly** when the cap is reached, instead of failing the workflow.
**Resolution.** Set `max-iterations` explicitly with `on-limit: fail` to make the workflow fail when the cap is hit:
```yaml
- name: poll
  type: while
  condition: "steps.check.output.status : 'pending'"
  max-iterations:
    limit: 10000
    on-limit: fail
  steps:
    - ...
```

Refer to [`while`](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/while).

### A `switch` step errors on save

**Symptom.** A `switch` step fails validation at save time.
**Cause.** The `cases` block is an array of objects, not a map.
**Resolution.** Structure `cases` as an array where each entry has `case:` and `steps:`:
```yaml
# Wrong
cases:
  foo:
    - { ... }
  bar:
    - { ... }

# Right
cases:
  - case: foo
    steps: [ { ... } ]
  - case: bar
    steps: [ { ... } ]
```

Refer to [`switch`](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/switch).

### `foreach` can't find the array

**Symptom.** A `foreach` loop errors or processes nothing.
**Cause.** The `foreach` value must be a Liquid expression that evaluates to an array. When passing a non-string value (an array or object), use the raw-value form `${{ ... }}` so the value isn't stringified.
**Resolution.** For step-level iteration or the `foreach` step:
```yaml
- name: process
  foreach: "${{ event.alerts }}"   
  steps: [ ... ]
```

Inside the loop, reference items as `foreach.item`, `foreach.index`, and `foreach.total`. Refer to [`foreach`](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/foreach).

## Cases and alerts


### `cases.addAlerts` rejects the `alerts` parameter

**Symptom.** `cases.addAlerts` fails validation with an `alerts` parameter error.
**Cause.** The `alerts` parameter takes an array of objects (each with `alertId` and `index`), not an array of ID strings.
**Resolution.**
```yaml
- name: attach
  type: cases.addAlerts
  with:
    case_id: "{{ steps.case.output.id }}"
    alerts:
      - alertId: "{{ event.alerts[0]._id }}"
        index:   "{{ event.alerts[0]._index }}"
        rule:
          id:   "{{ event.rule.id }}"
          name: "{{ event.rule.name }}"
```

Refer to [`cases.addAlerts`](/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/cases#cases-addalerts).

### `kibana.SetAlertsStatus` step type is rejected

**Symptom.** The workflow editor reports an unknown step type for `kibana.set_alerts_status` or similar.
**Cause.** The alert-management step types use PascalCase. Step type IDs are case-sensitive.
**Resolution.** Use the correct case:
- `kibana.SetAlertsStatus`
- `kibana.SetAlertTags`

Refer to [Kibana action steps](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/kibana).

### `cases.closeCase` rejects a `reason` field

**Symptom.** `cases.closeCase` fails validation when a `reason` parameter is included.
**Cause.** `cases.closeCase` doesn't accept a `reason` parameter.
**Resolution.** Document the reason with a `cases.addComment` call before closing:
```yaml
- name: note_why
  type: cases.addComment
  with:
    case_id: "{{ steps.case.output.id }}"
    comment: "Closing: confirmed duplicate of case XXX."

- name: close
  type: cases.closeCase
  with:
    case_id: "{{ steps.case.output.id }}"
```

Refer to [`cases.closeCase`](/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/cases#cases-closecase).

## Liquid and data flow


### `to_json` filter not found

**Symptom.** A Liquid expression using `to_json` fails with an unknown-filter error.
**Cause.** `to_json` doesn't exist. The workflow engine provides `json` to serialize and `json_parse` to parse.
**Resolution.**
```yaml
# Serialize a value to a JSON string
payload: "{{ event.alerts[0] | json }}"

# Parse a JSON string into an object
parsed: "{{ steps.http.output.body | json_parse }}"
```

Refer to [Liquid filters](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/reference/liquid-filters).

### An array is passed as a string

**Symptom.** A step expects an array but receives a stringified version of it, and the step fails validation.
**Cause.** The expression used `{{ ... }}` (string form) instead of `${{ ... }}` (raw-value form). The string form stringifies the value.
**Resolution.**
```yaml
# Wrong — renders the array as a string
items: "{{ event.alerts }}"

# Right — passes the array as an array
items: "${{ event.alerts }}"
```

Refer to [Templating engine](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/templating).

### `data.filter` condition is rejected

**Symptom.** A `data.filter` step fails with an invalid-condition error.
**Cause.** The `condition` field uses Kibana Query Language (KQL), not Liquid comparison syntax. KQL uses `:` for equality.
**Resolution.**
```yaml
# Wrong — Liquid comparison
condition: "item.severity == 'critical'"

# Right — KQL equality
condition: "item.severity : 'critical'"
```

The same applies to the `if` step's `condition`. Refer to [`data.filter`](/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/data#data-filter).

## AI steps


### An AI step rejects `connectorId`

**Symptom.** An `ai.prompt`, `ai.classify`, `ai.summarize`, or `ai.agent` step fails validation on `connectorId` or `connector_id`.
**Cause.** The parameter is `connector-id` (kebab-case) and lives at the step top level, not inside `with`.
**Resolution.**
```yaml
# Wrong
- type: ai.prompt
  with:
    connectorId: "my-openai"
    prompt: "..."

# Right
- type: ai.prompt
  connector-id: "my-openai"
  with:
    prompt: "..."
```

The same pattern applies to `agent-id` and `inference-id` on AI steps. Refer to [AI steps](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/ai-steps).

### `ai.summarize` rejects `content`

**Symptom.** An `ai.summarize` step fails validation on the `content` parameter.
**Cause.** The input parameter is named `input`, not `content`.
**Resolution.**
```yaml
- type: ai.summarize
  connector-id: "..."
  with:
    input: "${{ steps.gather.output }}"
```

Refer to [`ai.summarize`](/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/ai-steps#ai-summarize).

## Composition


### `workflow.execute` rejects `workflow_id`

**Symptom.** A `workflow.execute` or `workflow.executeAsync` step fails validation on the `workflow_id` or `workflowId` parameter.
**Cause.** The parameter is `workflow-id` (kebab-case), and it lives inside `with`. Composition steps are the one exception to the top-level-kebab-case convention used by AI steps.
**Resolution.**
```yaml
- name: run_child
  type: workflow.execute
  with:
    workflow-id: "shared--enrich-documents"
    inputs:
      documents: "${{ event.alerts }}"
```

Refer to [Composition steps](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/steps/composition).

## Human-in-the-loop


### A paused execution is stuck

**Symptom.** A workflow paused by `waitForInput` never resumes.
**Cause.** `waitForInput` doesn't time out by default. The workflow waits indefinitely until someone submits the resume form or calls the resume API.
**Resolution.** To limit the wait, set a workflow-level `settings.timeout`. The workflow cancels when the timeout elapses.
```yaml
settings:
  timeout: "24h"
```

Refer to [Human-in-the-loop](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/authoring-techniques/human-in-the-loop).

## Execution and concurrency


### An execution was `skipped`

**Symptom.** An execution appears in history with state `skipped`.
**Cause.** The workflow's `concurrency.strategy` is `drop` and another execution was already running for the same `key` when this one was due to start.
**Resolution.** This is the intended behavior of `drop`. If you want the new run to cancel the old one instead, use `strategy: cancel-in-progress`.
```yaml
settings:
  concurrency:
    key: "{{ event.alerts[0].host.name }}"
    strategy: cancel-in-progress
    max: 1
```


### A workflow cancelled mid-execution

**Symptom.** A workflow terminated with a `cancelled` state.
**Cause.** One of:
- `settings.timeout` — the workflow's overall time budget was exceeded.
- Concurrency with `cancel-in-progress` — a new execution kicked this one out.
- Operator cancel — someone clicked **Cancel all** in the UI.

**Resolution.** The execution view shows the cancellation reason on the terminal state. Review it and adjust `settings.timeout` or the concurrency strategy if needed.

## Setup and permissions


### You can't create workflows

**Symptom.** The **Create a new workflow** button is disabled, or the editor rejects save attempts.
**Cause.** Your user role is missing one of the Workflows feature privileges.
**Resolution.** Ensure your role has at least `All` on the **Analytics > Workflows** feature. For finer-grained access, 9.4 introduces seven granular sub-feature privileges: `create`, `read`, `update`, `delete`, `execute`, `readExecution`, and `cancelExecution`. Refer to [Setup](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/get-started/setup).

### Workflows isn't visible in Kibana

**Symptom.** The **Workflows** navigation entry doesn't appear in Kibana.
**Cause.** The `workflows:ui:enabled` advanced setting has been disabled, or the deployment doesn't have the required license or subscription tier.
**Resolution.** In 9.4, `workflows:ui:enabled` defaults to `true`. If it has been explicitly disabled, re-enable it in **Advanced settings**. Confirm the deployment is on a supported tier (Enterprise license on Elastic Cloud Hosted or self-managed, or a Serverless project of the required type). Refer to [Setup](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/get-started/setup).

## Still stuck

- Search this documentation for error messages or parameter names.
- Review the [Cheat sheet](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/reference/cheat-sheet) for quick syntax references.
- Review the [Step type index](https://www.elastic.co/elastic/docs-builder/docs/3276/explore-analyze/workflows/reference/step-types) for the full catalog.
- File an issue on the [Kibana GitHub repo](https://github.com/elastic/kibana/issues/new/choose) with a minimal reproduction.