Data Flow & Type Handling
Learn how data flows between nodes in workflows and handle data types correctly to avoid runtime errors.
Overview
In workflows, data flows from one node to the next by referencing outputs from previous nodes or workflow inputs. You control this data flow using {{...}} reference syntax. Each field has a specific data type, and type compatibility is critical for successful workflow execution.
Key Concepts:
Workflow inputs and node outputs have defined types
Node inputs expect specific types
Type mismatches cause workflow failures at runtime
Type conversion nodes help transform data between incompatible types
How Data Flows in Workflows
Understanding how data moves through your workflow is essential for building reliable automations.
Workflow Execution Flow
Workflows execute linearly from top to bottom, with data passing from one node to the next:
1. User provides workflow inputs
↓
2. Node 1 executes → produces outputs
↓
3. Node 2 executes (can reference Node 1 outputs) → produces outputs
↓
4. Node 3 executes (can reference Node 1 & 2 outputs) → produces outputs
↓
5. Workflow returns final outputAvailable Data at Each Node
Each node can access:
Workflow inputs: Data provided when the workflow starts
Previous node outputs: Results from any node that executed before it
Cannot access: Future node outputs (nodes that haven't executed yet)
Example:
Node 1: fetch_user
Can access: workflow inputs only
Node 2: analyze_data
Can access: workflow inputs + fetch_user outputs
Node 3: send_email
Can access: workflow inputs + fetch_user outputs + analyze_data outputsControlling Data Flow
You control what data flows between nodes by:
Referencing specific fields - Choose exactly which data to pass
Transforming data - Use conversion techniques to match types
Combining data - Merge multiple sources into one field
How to Reference Data
Use double curly braces {{...}} to reference data in node configurations and text fields:
Reference Workflow Inputs
{{input_field_name}}Example:
{
"url": "{{website_url}}",
"email": "{{user_email}}"
}Reference Node Outputs
{{node_name.output_field}}Example:
{
"content": "{{web_scraper.html}}",
"summary": "{{llm_analyzer.result}}"
}Use in Text Strings
You can embed references inside text strings - they will always be converted to string type:
{
"message": "Hello {{user_name}}, your order #{{order_id}} is ready!",
"subject": "Analysis complete: {{analyzer.status}}",
"body": "Found {{search_results.count}} results for {{query}}"
}Important: When used in strings, all values are automatically converted to text:
Numbers become strings:
{{count}}→"42"Objects become JSON strings:
{{user}}→'{"name":"John"}'Arrays become JSON strings:
{{items}}→'["a","b","c"]'
Nested Field Access
Access nested objects and arrays:
{{node_name.data.users[0].name}}
{{api_response.result.items[2].id}}Understanding Data Types
Every field in workflow inputs, node inputs, and node outputs has a specific data type defined in its schema.
Common Data Types
number
Numeric values (int or float)
42, 3.14, -10
boolean
True/false values
true, false
object
JSON objects/dictionaries
{"name": "John", "age": 30}
array
Lists of items
[1, 2, 3], ["a", "b", "c"]
How to Check Field Types
1. Workflow Input Types When defining workflow inputs, you specify the type:
{
"user_email": {
"type": "string",
"title": "User Email"
},
"max_results": {
"type": "number",
"title": "Maximum Results"
}
}2. Node Input and Output Types Each node defines its input and output types in its schema. Check the node's detail page to see:
What input types each field expects
What output types each field produces
Where to find node type information:
Node Reference Documentation - Browse all 193+ nodes by category
Individual node detail pages - Shows complete input/output schemas
Visual builder node panel - Displays field types when configuring nodes
Type Compatibility Rules
✅ Compatible Substitution
You can substitute a field if the types match exactly:
// Workflow input: user_email (string)
// Node 1 output: email_address (string)
// Node 2 input: recipient (string)
{
"recipient": "{{user_email}}" // ✅ string → string
}
{
"recipient": "{{node_1.email_address}}" // ✅ string → string
}❌ Incompatible Substitution
Type mismatches will cause runtime errors:
// Node 1 output: user_data (object)
// Node 2 input: email (string)
{
"email": "{{node_1.user_data}}" // ❌ object → string
}Error at runtime:
Type mismatch: Expected string, got objectExample: Type Mismatch Scenario
Workflow Setup:
Node 1: api_call
Output: response (object) = {"users": [{"email": "[email protected]"}]}
Node 2: send_email
Input: recipient (string)Incorrect Configuration:
{
"recipient": "{{api_call.response}}" // ❌ Fails!
}Error: Cannot assign object to string field.
Correct Configuration:
{
"recipient": "{{api_call.response.users[0].email}}" // ✅ Works!
}Access the nested string field directly.
Type Conversion Techniques
When you need to connect fields with different types, use these techniques:
1. String to JSON (Object/Array)
Use Case: Convert JSON string to object or array
Node: string_to_json
Example:
Node 1: api_call
Output: json_string (string) = '{"name": "John", "age": 30}'
Node 2: string_to_json
Input: string_to_convert (string) = "{{api_call.json_string}}"
Output: json_output (object) = {"name": "John", "age": 30}
Node 3: process_user
Input: user_object (object) = "{{string_to_json.json_output}}"2. Object/Array to String
Use Case: Convert object or array to string
Technique: Use string interpolation (automatic conversion)
{
"text_field": "User data: {{object_node.data}}",
"message": "Items: {{array_node.items}}"
}When embedded in strings, objects and arrays are automatically converted to JSON string format.
3. Number to String
Use Case: Convert numeric values to text
Technique: Use string interpolation (automatic conversion)
{
"message": "Count: {{counter_node.value}}",
"id": "ID-{{order_id}}"
}Numbers are automatically converted to strings when embedded in text.
4. Extract Array Item
Use Case: Get a single item from an array
Technique: Use array indexing
{
"first_user": "{{users_node.list[0]}}",
"last_item": "{{items[2]}}"
}5. Extract Object Field
Use Case: Get a specific field from an object
Technique: Use dot notation
{
"user_name": "{{user_object.name}}",
"user_age": "{{user_object.age}}",
"nested_value": "{{data.results.items[0].id}}"
}6. Custom Transformations with Code
Use Case: Complex type conversions and data transformations
Available Nodes:
run_javascript- Execute JavaScript code for transformationsrun_python_code- Execute Python code for transformations
Example (JavaScript):
// Input: data_array (array of objects)
// Output: CSV string
const headers = Object.keys(data_array[0]).join(',');
const rows = data_array.map(obj =>
Object.values(obj).join(',')
).join('\n');
return headers + '\n' + rows;Example (Python):
# Input: items (array)
# Output: formatted_list (string)
formatted = '\n'.join([f"- {item}" for item in items])
return formattedCommon Type Mismatch Scenarios
Scenario 1: API Response to Email Body
Problem:
// API returns: {"status": "success", "message": "Done"}
// Email expects: string
{
"email_body": "{{api_call.response}}" // ⚠️ May not be what you want
}This will work (objects are auto-converted to JSON strings), but you'll get:
{"status":"success","message":"Done"}Better Solutions:
Solution A: Access the specific field you want
{
"email_body": "{{api_call.response.message}}" // ✅ Returns: "Done"
}Solution B: Format it nicely in a string
{
"email_body": "Status: {{api_call.response.status}}, Message: {{api_call.response.message}}"
// ✅ Returns: "Status: success, Message: Done"
}Solution C: Use the whole object if you want JSON
{
"email_body": "API Response: {{api_call.response}}"
// ✅ Returns: 'API Response: {"status":"success","message":"Done"}'
}Scenario 2: String ID to Number ID
Problem:
// Node 1 returns: user_id (string) = "12345"
// Node 2 expects: id (number)
{
"id": "{{node_1.user_id}}" // ❌ Type error: string → number
}Solution: Use run_javascript or run_python_code to convert
// JavaScript
return parseInt(user_id); // Converts "12345" → 12345# Python
return int(user_id) # Converts "12345" → 12345Scenario 3: Multiple Values to Array
Problem:
// Need array of emails
// Have: email1 (string), email2 (string)
{
"recipients": "{{email1}}, {{email2}}" // ❌ string, not array
}Solution: Use array construction
{
"recipients": ["{{email1}}", "{{email2}}"] // ✅
}Type Validation and Error Messages
Runtime Type Errors
When types don't match, workflows fail with clear error messages:
Example Error:
Node: send_email (step 3)
Field: recipient
Error: Type validation failed
Expected: string
Received: object
Value: {"email": "[email protected]", "name": "John"}How to Fix Type Errors
Check the error message - identifies the node, field, expected type, and actual type
Review node documentation - confirm expected input types
Inspect previous node outputs - verify what type is being produced
Add conversion node - insert appropriate type conversion between nodes
Adjust substitution - use dot notation or array indexing to access correct type
Best Practices
1. Verify Types Before Substituting
Always check:
What type does the source field produce?
What type does the target field expect?
Do they match?
2. Use Node Documentation
Refer to the Node Reference to understand:
Input schemas (expected types)
Output schemas (produced types)
3. Test Incrementally
Build workflows step-by-step:
Add a node
Configure inputs with substitution
Run and verify output types
Continue to next node
4. Add Type Conversion Early
If you know types don't match:
Insert conversion nodes immediately
Don't wait for runtime errors
5. Use Explicit Field Access
Instead of:
{"data": "{{api_node.response}}"} // May be wrong typeUse:
{"data": "{{api_node.response.data.result}}"} // Explicit field6. Handle Arrays Carefully
Remember:
{{node.items}}→ entire array{{node.items[0]}}→ first item{{node.items[0].name}}→ field from first item
Type Conversion Node Reference
Available nodes and techniques for type conversion:
String → Object/Array
string_to_json node
Parse '{"a":1}' → {a: 1}
Object/Array → String
String interpolation
"Data: {{obj}}" → 'Data: {"a":1}'
Number → String
String interpolation
"Count: {{num}}" → "Count: 42"
String → Number
run_javascript / run_python_code
parseInt("42") → 42
Array → String
String interpolation
"Items: {{arr}}" → 'Items: [1,2,3]'
Extract from Array
Array indexing
{{arr[0]}} → first item
Extract from Object
Dot notation
{{obj.field}} → field value
Custom Transform
run_javascript / run_python_code
Any complex conversion
Key Nodes:
string_to_json- Parse JSON strings to objects/arraysrun_javascript- Execute JavaScript for custom transformationsrun_python_code- Execute Python for custom transformationsget_value_by_key- Extract value from object by key name
See Utilities Nodes for complete list.
Troubleshooting Guide
Issue: "Type mismatch" error at runtime
Solution:
Check error message for expected vs. actual type
Add conversion node between incompatible nodes
Use dot notation to access nested fields of correct type
Issue: "Cannot read property of undefined"
Solution:
Verify previous node executed successfully
Check field name spelling:
{{node.field}}must match exactlyEnsure previous node actually outputs that field
Issue: "Invalid JSON" error
Solution:
Verify string is valid JSON before using
string_to_jsonCheck for escaped quotes or formatting issues
Test JSON string in external validator
Issue: Array indexing fails
Solution:
Verify array is not empty: check previous node output
Use valid index:
[0]for first item, not[1]Handle potential empty arrays in workflow logic
Related Documentation
Node Reference - Complete node type documentation
Utilities Nodes - Type conversion nodes
Troubleshooting Workflows - Common workflow errors
Complete Example: Step-by-Step Workflow Execution
Let's walk through a real workflow execution to see exactly what data is available at each step and how the workflow state changes.
Workflow Setup
Workflow Definition:
{
"name": "API Analysis Workflow",
"input_schema": {
"type": "object",
"properties": {
"api_url": {
"type": "string",
"title": "API URL"
},
"recipient_email": {
"type": "string",
"title": "Recipient Email"
}
}
}
}📊 STEP 1: User Starts Workflow
User provides inputs:
{
"api_url": "https://api.example.com/users/123",
"recipient_email": "[email protected]"
}Workflow State:
{
"inputs": {
"api_url": "https://api.example.com/users/123",
"recipient_email": "[email protected]"
},
"nodes": {}
}What you can reference:
✅
{{api_url}}→"https://api.example.com/users/123"✅
{{recipient_email}}→"[email protected]"❌ No node outputs available yet
📊 STEP 2: Node 1 (fetch_data) Executes
Node Configuration:
{
"name": "fetch_data",
"node_type_name": "api_call",
"input_config": {
"url": "{{api_url}}",
"method": "GET"
}
}After {{...}} substitution, node receives:
{
"url": "https://api.example.com/users/123",
"method": "GET"
}Node executes and produces output:
{
"status_code": 200,
"response_body": {
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"status": "active"
}
}Workflow State after Node 1:
{
"inputs": {
"api_url": "https://api.example.com/users/123",
"recipient_email": "[email protected]"
},
"nodes": {
"fetch_data": {
"status_code": 200,
"response_body": {
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"status": "active"
}
}
}
}What you can now reference:
✅
{{api_url}}→"https://api.example.com/users/123"✅
{{recipient_email}}→"[email protected]"✅
{{fetch_data.status_code}}→200✅
{{fetch_data.response_body}}→{"id": 123, "name": "John Doe", ...}✅
{{fetch_data.response_body.name}}→"John Doe"✅
{{fetch_data.response_body.status}}→"active"❌ Cannot reference nodes that haven't executed yet
📊 STEP 3: Node 2 (analyze_user) Executes
Node Configuration:
{
"name": "analyze_user",
"node_type_name": "claude_ask",
"input_config": {
"prompt": "Analyze this user data: Name is {{fetch_data.response_body.name}}, status is {{fetch_data.response_body.status}}",
"model": "claude-3-5-sonnet-latest",
"max_tokens": 500
}
}After {{...}} substitution, node receives:
{
"prompt": "Analyze this user data: Name is John Doe, status is active",
"model": "claude-3-5-sonnet-latest",
"max_tokens": 500
}Node executes and produces output:
{
"content": "This user John Doe appears to be an active account holder in good standing."
}Workflow State after Node 2:
{
"inputs": {
"api_url": "https://api.example.com/users/123",
"recipient_email": "[email protected]"
},
"nodes": {
"fetch_data": {
"status_code": 200,
"response_body": {
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"status": "active"
}
},
"analyze_user": {
"content": "This user John Doe appears to be an active account holder in good standing."
}
}
}What you can now reference:
✅ All workflow inputs
✅ All
fetch_dataoutputs✅
{{analyze_user.content}}→"This user John Doe appears to be..."❌ Cannot reference nodes that haven't executed yet
📊 STEP 4: Node 3 (send_report) Executes
Node Configuration:
{
"name": "send_report",
"node_type_name": "send_email",
"input_config": {
"recipient_emails": ["{{recipient_email}}"],
"subject": "User Analysis Report",
"body": "Analysis for {{fetch_data.response_body.name}}:\n\n{{analyze_user.content}}"
}
}After {{...}} substitution, node receives:
{
"recipient_emails": ["[email protected]"],
"subject": "User Analysis Report",
"body": "Analysis for John Doe:\n\nThis user John Doe appears to be an active account holder in good standing."
}Node executes and produces output:
{
"message": "Email sent successfully",
"email_id": "msg_abc123xyz"
}Final Workflow State after Node 3:
{
"inputs": {
"api_url": "https://api.example.com/users/123",
"recipient_email": "[email protected]"
},
"nodes": {
"fetch_data": {
"status_code": 200,
"response_body": {
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"status": "active"
}
},
"analyze_user": {
"content": "This user John Doe appears to be an active account holder in good standing."
},
"send_report": {
"message": "Email sent successfully",
"email_id": "msg_abc123xyz"
}
}
}What you can now reference:
✅ All workflow inputs
✅ All outputs from all executed nodes
✅
{{send_report.message}}→"Email sent successfully"✅
{{send_report.email_id}}→"msg_abc123xyz"
📊 STEP 5: Workflow Completes
If no output mapping is defined:
The workflow returns the last node's output:
{
"message": "Email sent successfully",
"email_id": "msg_abc123xyz"
}If output mapping is defined:
{
"output_mapping": {
"user_name": "{{fetch_data.response_body.name}}",
"analysis": "{{analyze_user.content}}",
"email_status": "{{send_report.message}}"
}
}The workflow returns:
{
"user_name": "John Doe",
"analysis": "This user John Doe appears to be an active account holder in good standing.",
"email_status": "Email sent successfully"
}Key Observations from This Example
1. Data Accumulates as You Go:
After Node 1: Can reference → inputs + fetch_data
After Node 2: Can reference → inputs + fetch_data + analyze_user
After Node 3: Can reference → inputs + fetch_data + analyze_user + send_report2. Cannot Reference Future Nodes:
At Node 1, you CANNOT use
{{analyze_user.content}}(hasn't run yet)At Node 2, you CANNOT use
{{send_report.message}}(hasn't run yet)
3. String Interpolation:
"Name is {{fetch_data.response_body.name}}"→"Name is John Doe"Numbers become strings: If
idwas in the string,"ID: {{fetch_data.response_body.id}}"→"ID: 123"Objects become JSON:
"Data: {{fetch_data.response_body}}"→"Data: {\"id\":123,\"name\":\"John Doe\"...}"
4. Exact Field Names Matter:
✅
{{fetch_data.response_body}}(correct - matchesApiCallNodeOutput)❌
{{fetch_data.response}}(wrong - field doesn't exist)✅
{{analyze_user.content}}(correct - matchesAskClaudeOutput)❌
{{analyze_user.response}}(wrong - field doesn't exist)
5. Check Node Documentation:
Each node type has specific input and output field names
Always refer to Node Reference for exact field names
Summary
Key Takeaways:
Data Flow:
✅ Workflows execute top-to-bottom, data flows linearly between nodes
✅ Each node can access workflow inputs and outputs from previous nodes
✅ Use
{{...}}syntax to reference data from inputs and previous nodes
Type Handling: 4. ✅ All fields in workflow inputs, node inputs, and node outputs have defined types 5. ✅ Types must match when passing values between nodes 6. ✅ Type mismatches cause runtime errors, not design-time warnings 7. ✅ Check node detail pages to see input/output types
Automatic Conversions: 8. ✅ When embedded in strings, all values auto-convert to strings 9. ✅ Objects and arrays become JSON strings: "Data: {{obj}}" works 10. ✅ Numbers become text: "Count: {{num}}" works
Manual Conversions: 11. ✅ Use string_to_json to parse JSON strings to objects/arrays 12. ✅ Use run_javascript or run_python_code for complex transformations 13. ✅ Use dot notation and array indexing to extract specific values
Best Practices: 14. ✅ Test workflows incrementally to catch type errors early 15. ✅ Use explicit field access: {{api.response.data.id}} vs {{api.response}}
Remember: When in doubt, check the node's detail page for exact input/output types!
Last updated
Was this helpful?