Why isn't my email sending? Why does my AI Employee say the same thing three times? This debugging guide covers the most common workflow problems and shows you exactly how to diagnose and fix them—with real examples from production workflows.

The Debugging Mindset

Before diving into specific problems, understand the rules that govern workflow execution:

Rule Implication
Reachability A node must have an execution path from trigger
Trigger gating Classifier outputs must connect to trigger_when for conditional paths
Required inputs All required inputs must be produced and connected
Dependency sync If one upstream never fires, downstream nodes stall
Side effects need reachability Email/API calls need both data AND trigger paths

Keep these in mind as we diagnose specific issues.


Problem 1: Email Never Sends

This is the #1 support question. Your workflow has an email node, but emails never go out.

Cause 1A: Email Node is Disconnected (Unreachable)

Symptoms: Email node exists but never executes.

Diagnosis: Check if the node has an upstream path from trigger.

flowchart LR
    subgraph connected["Connected Path ✓"]
        T["Trigger"] --> C["Classifier"] --> A["Agent"] --> O["WORKFLOW_OUTPUT"]
    end

    subgraph disconnected["Disconnected ✗"]
        FR["Fixed Response"] --> SE["Send Email"]
    end

    style disconnected fill:#ffcdd2,stroke:#c62828

Problem: The email node has inputs wired but no path from trigger activates it.

What happens: The email node has inputs wired (subject, to, body), but nothing in the graph ever "activates" it. There's no upstream path from trigger.

Fix:

  1. Connect a routing classifier output to the email node's trigger_when
  2. Or wire the email node into the main execution flow
# Before: No trigger path
send_email:
  inputs:
    subject: fixed_response.subject
    to: fixed_response.to
    body: fixed_response.body
  # No trigger_when = never runs if disconnected

# After: Explicit routing
send_email:
  trigger_when: chat_categorizer.category == "send-email"
  inputs:
    subject: construct_subject.response
    to: construct_to.response
    body: construct_body.response

Cause 1B: Missing Trigger Gating on Email Path

Symptoms: Email node is connected but still doesn't run.

Diagnosis: The email path depends on upstream nodes that are gated by categories that don't fire.

flowchart TD
    CL["Classifier"]

    CL -->|"category::identify_caller"| EE["Entity Extraction"]
    EE --> CE["Construct To Email"]
    CE --> SE["Send Email"]

    CL -->|"category::generate-response"| OP["Other Path"]

    style EE fill:#fff9c4
    style CE fill:#fff9c4
    style SE fill:#fff9c4

Problem: If classifier outputs "generate-response" but not "identify_caller", the email path never gets its to_email input.

Failure mode: If the routing classifier doesn't emit category::identify_caller for the conversation, entity extraction never runs → to_email is never populated → email send fails.

Fix:

  1. Don't gate user resolution behind a separate category if email always needs it
  2. Gate the ENTIRE email flow behind a single "send email" category
  3. Provide fallback email sources
# Option 1: Run user resolution unconditionally
entity_extraction:
  # No trigger_when - always runs
  inputs:
    conversation: trigger.chat_conversation

# Option 2: Gate entire email flow together
send_email_flow:
  trigger_when: classifier.category == "send-email"
  # All email-related nodes share this gate

Cause 1C: Malformed Data in Email Fields

Symptoms: Email node runs but fails validation or sends garbage.

Diagnosis: Check what's being wired to subject, to_email, body.

Common mistake: Using response_with_sources instead of clean output

# ❌ BAD: response_with_sources may contain citations, metadata
send_email:
  to_email: call_llm.response_with_sources
  # Result: "The email is john@example.com [Source: client-db]"

# ✅ GOOD: Use clean response output
send_email:
  to_email: call_llm.response
  # Result: "john@example.com"

Better: Force structured JSON output

call_llm_email_address:
  instructions: |
    Extract the recipient email address.
    Output ONLY valid JSON: {"email": "user@domain.com"}
    No explanation, no sources, just JSON.

json_extractor:
  input: call_llm_email_address.response
  path: $.email

send_email:
  to_email: json_extractor.email # Clean value

Email Debugging Checklist

Check What to Look For
1. Reachability Does the email node have a path from trigger?
2. Trigger gating Is trigger_when connected to the right category?
3. Upstream dependencies Do ALL upstream nodes (to, subject, body) actually run?
4. Data format Is to_email a clean email string, not response_with_sources?
5. Required inputs Are subject, to, body ALL populated?

Problem 2: Agent Repeats the Same Thing 3 Times

Your AI Employee responds with the same message multiple times. This is almost always caused by multiple responder nodes running in parallel.

Cause 2A: Multiple Unguarded "Final Responders"

Symptoms: Every message produces 2-3 identical (or similar) responses.

Diagnosis: Check what feeds into WORKFLOW_OUTPUT:

flowchart LR
    FH["Fallback Handler<br/>(no trigger_when)<br/>ALWAYS runs!"]
    FR["Fallback Response<br/>(gated by Fallback)"]
    SE["Send Email Handler<br/>(email_result)"]
    WO["WORKFLOW_OUTPUT"]

    FH --> WO
    FR --> WO
    SE --> WO

    style FH fill:#ffcdd2

Result: Up to 3 outputs displayed as chat messages!

Key culprit: Ungated fallback handlers

If a node has no trigger_when and receives input from an always-running node (like conversation_summarizer), it runs on every single turn.

Fix:

  1. Gate ALL responder nodes with trigger_when
  2. Ensure only ONE path to WORKFLOW_OUTPUT is active per turn
# ❌ BAD: No gate = always runs
fallback_handler:
  inputs:
    query: conversation_summarizer.summarized_conversation
  # Runs every turn, even when classifier routes elsewhere!

# ✅ GOOD: Explicit gate
fallback_handler:
  trigger_when: classifier.category == "general-question"
  inputs:
    query: conversation_summarizer.summarized_conversation

Cause 2B: Redundant Classifiers with Overlapping Categories

Symptoms: Different branches activate for the same input.

Diagnosis: Check if you have multiple classifiers analyzing the same input:

flowchart TD
    T["Trigger"]

    T --> IC1["Intent Classifier 1"]
    IC1 -->|"Fallback"| FR1["Fallback Response 1"]

    T --> CC["Chat Categorizer"]
    CC -->|"generate-response"| RH["Response Handler"]

    style IC1 fill:#ffcdd2
    style CC fill:#ffcdd2

Problem: Both classifiers analyze same input independently. If input is ambiguous, BOTH downstream nodes run.

Fix: Consolidate into a single classifier with mutually exclusive categories:

# ❌ BAD: Two classifiers = potential overlap
intent_classifier:
  categories: [Fallback, ...]

chat_categorizer:
  categories: [generate-response, send-email, ...]

# ✅ GOOD: Single classifier with all categories
unified_classifier:
  categories:
    - SEND_EMAIL: "Requests to send communications"
    - PORTFOLIO_REVIEW: "Questions about portfolio"
    - FALLBACK: "Unclear or general requests"
  # Only ONE category per turn = only ONE path runs

Cause 2C: Ungated Email Pipeline Producing Chat Output

Symptoms: Email confirmation appears as a chat response alongside the actual answer.

Diagnosis: The email pipeline runs when it shouldn't, and its output is rendered as chat.

# Problem nodes (no trigger_when):
construct_email_subject:
  # No gate - always runs

construct_to_email:
  # No gate - always runs

extract_email_body:
  # No gate - always runs

send_email_handler:
  # Runs when all inputs arrive
  # Returns email_result that gets displayed

Fix:

  1. Gate email pipeline nodes behind "send-email" category
  2. Don't display email_result as chat message
# Gate the entire email pipeline
construct_email_subject:
  trigger_when: classifier.category == "send-email"

send_email_handler:
  trigger_when: classifier.category == "send-email"

Cause 2D: Trigger Fires Multiple Times Per Message

Symptoms: Entire workflow runs 2-3 times for one user message.

Diagnosis: Check trigger configuration—it may fire on:

  • Message creation AND update
  • Each speech-to-text chunk (partial transcripts)
  • Retries after timeouts

Fix:

  1. Configure trigger for "final message only"
  2. Add idempotency by tracking processed message IDs
  3. If using speech-to-text, wait for final transcript
# Ensure trigger fires once per finalized message
chat_trigger:
  fire_on: "message_finalized" # Not "message_created" + "message_updated"
  dedupe_by: "message_id"

Cause 2E: Retry Behavior Duplicates Outputs

Symptoms: Same response appears multiple times, often with slight delays between them.

Diagnosis: Platform-level retries on LLM timeouts or errors.

Fix:

  1. Reduce retry count for chat-visible nodes
  2. Make side-effect actions idempotent (dedupe key for emails)

Repetition Debugging Checklist

Check What to Look For
1. Multiple responders How many nodes feed into WORKFLOW_OUTPUT?
2. Ungated handlers Does fallback_handler have a trigger_when?
3. Overlapping classifiers Are there multiple classifiers that could both fire?
4. Email as chat output Is email_result being displayed as a message?
5. Trigger frequency Does trigger fire once or multiple times per message?
6. Retry settings Are LLM nodes retrying and producing duplicate outputs?

Problem 3: Workflow Gets Stuck (No Response)

Your AI Employee starts processing but never produces output.

Cause 3A: Dependency Deadlock

Symptoms: Workflow starts but never completes.

Diagnosis: A node waits for inputs that never arrive because upstream nodes are gated.

flowchart TD
    A["Node A<br/>trigger_when: category == 'path-a'"]
    B["Node B<br/>trigger_when: category == 'path-b'"]
    C["Node C<br/>Waits for BOTH A and B"]

    A -->|"input_1"| C
    B -->|"input_2"| C

    style B fill:#ffcdd2
    style C fill:#fff9c4

Problem: If classifier outputs "path-a", Node B never runs. Node C waits forever for node_b.output.

Fix:

  1. Don't require inputs from mutually exclusive branches
  2. Use optional inputs or defaults
  3. Restructure to separate branches

Cause 3B: Unused Search Results (Dead Branch)

Symptoms: Workflow runs knowledge search but then does nothing with results.

Diagnosis: knowledge_search.search_results has no downstream consumers.

# Problem: Search runs but output goes nowhere
knowledge_search:
  trigger_when: category == "generate-response"
  inputs:
    query: summarizer.output
  # search_results not connected to anything!

# Fix: Connect results to consuming node
custom_agent:
  named_inputs:
    - SearchResults: knowledge_search.search_results # ← Add this

Problem 4: Loops and Infinite Execution

Your workflow runs endlessly or produces cascading outputs.

Cause: Cyclic Dependencies Without Exit Condition

Symptoms: Multiple executions, growing outputs, or timeout.

Diagnosis: Look for cycles in your node graph:

flowchart LR
    A["Agent A"] --> FR["Fixed Response"] --> S["Search"]
    S --> EE["Entity Extraction"]
    EE --> A

    style A fill:#ffcdd2
    style EE fill:#ffcdd2

Problem: If nodes re-run on updated inputs, this loops forever.

Fix:

  1. Break the cycle—make resolution a one-pass step
  2. Add explicit exit conditions
  3. Ensure only one node produces the "final" value

Quick Diagnostic Reference

Problem Most Likely Cause First Thing to Check
Email never sends Node unreachable Does email node have path from trigger?
Email fails validation Malformed data Is to_email clean or response_with_sources?
Triple response Ungated handlers Does fallback_handler have trigger_when?
Same response twice Overlapping classifiers Are there multiple classifiers?
Workflow stuck Dependency deadlock Are required inputs from gated nodes?
Infinite loop Cyclic dependencies Is there a cycle in the graph?

Summary: The Debugging Rules

Rule Check
Reachability Every node must have a path from trigger
Gating Use trigger_when to make branches mutually exclusive
Single responder Only ONE path should produce chat output per turn
Data mapping Use clean outputs, not response_with_sources
Dependencies Don't wait for inputs from gated nodes that might not run
Consolidation Use ONE classifier, not multiple overlapping ones

The golden rule: For any user message, exactly ONE path should execute and produce exactly ONE response. If multiple paths can run, you'll get multiple outputs. If no path runs, you'll get nothing.


For more on routing patterns, see Ema Workflows: Routing and Branching. For entity extraction issues, see Ema Workflows: Mastering Entity Extraction.