Troubleshoot workflows
Quick answers to the issues first-time workflow authors hit most often. Each section states the symptom, the cause, and the resolution.
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 for the full setup sequence.
Symptom. A previously working scheduled workflow stops executing.
Cause. One of three common causes:
- The workflow was disabled (
enabled: false). - 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. - A
dropconcurrency 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.
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::
triggers:
- type: workflows.failed
on:
condition: "event.workflow.name : 'ops--rollback-deployment'"
Refer to Event-driven triggers.
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:
- name: poll
type: while
condition: "steps.check.output.status : 'pending'"
max-iterations:
limit: 10000
on-limit: fail
steps:
- ...
Refer to while.
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::
# Wrong
cases:
foo:
- { ... }
bar:
- { ... }
# Right
cases:
- case: foo
steps: [ { ... } ]
- case: bar
steps: [ { ... } ]
Refer to switch.
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:
- name: process
foreach: "${{ event.alerts }}"
steps: [ ... ]
- raw-value form for an array
Inside the loop, reference items as foreach.item, foreach.index, and foreach.total. Refer to foreach.
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.
- 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.
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.SetAlertsStatuskibana.SetAlertTags
Refer to Kibana action steps.
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:
- 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.
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.
# 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.
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.
# Wrong — renders the array as a string
items: "{{ event.alerts }}"
# Right — passes the array as an array
items: "${{ event.alerts }}"
Refer to Templating engine.
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.
# 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.
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.
# 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.
Symptom. An ai.summarize step fails validation on the content parameter.
Cause. The input parameter is named input, not content.
Resolution.
- type: ai.summarize
connector-id: "..."
with:
input: "${{ steps.gather.output }}"
Refer to ai.summarize.
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.
- name: run_child
type: workflow.execute
with:
workflow-id: "shared--enrich-documents"
inputs:
documents: "${{ event.alerts }}"
Refer to Composition steps.
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.
settings:
timeout: "24h"
Refer to Human-in-the-loop.
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.
settings:
concurrency:
key: "{{ event.alerts[0].host.name }}"
strategy: cancel-in-progress
max: 1
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.
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.
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.
- Search this documentation for error messages or parameter names.
- Review the Cheat sheet for quick syntax references.
- Review the Step type index for the full catalog.
- File an issue on the Kibana GitHub repo with a minimal reproduction.