> ## Documentation Index
> Fetch the complete documentation index at: https://docs.liberate.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Code node

# Code Node

The **Code Node** lets you write and execute custom JavaScript or Python code within your workflow. Use it when JSONata expressions in Mapping Nodes aren't sufficient for your logic requirements.

> [!NOTE]
>
> The Code Node provides full programming flexibility. Use it for complex calculations, custom validations, data transformations that exceed JSONata capabilities, or integrating custom business logic.

## Overview

Use a Code Node when you need to:

* Perform complex calculations or algorithms
* Implement custom validation logic
* Work with dates and times in sophisticated ways
* Loop through arrays with complex transformations
* Call utility functions or libraries
* Handle edge cases that JSONata can't express

***

## When to Use Code Node vs. Other Nodes

| Task | Best Node |
| - | - |
| Simple field mapping | Mapping Node |
| Concatenate strings | Mapping Node |
| Complex date calculations | **Code Node** ✅ |
| Loop with conditional logic | **Code Node** ✅ |
| Parse unstructured text | AI Prompt Node |
| Call external API | Task Node |
| Simple conditional routing | Decision Table Node |
| Complex business rules | **Code Node** ✅ |

> [!TIP]
>
> Start with Mapping Node for data transformations. Only use Code Node when you hit JSONata's limitations.

***

## Configuration

Click on a Code Node to open its configuration panel.

### Basic Settings

| Setting | Description |
| - | - |
| **Title** | Descriptive name for the node |
| **Language** | JavaScript or Python |
| **Code** | Your custom code |

### Language Options

> [tab] JavaScript
>
> * Familiar syntax for web developers
> * Access to standard JavaScript built-ins
> * ES6+ features supported
>
> ```javascript theme={null}
> // Your code here
> const result = context.value * 2;
> return { ...context, result };
> ```

> [tab] Python
>
> * Clean, readable syntax
> * Great for data manipulation
> * Standard Python libraries available
>
> ```python theme={null}
> # Your code here
> result = context['value'] * 2
> return {**context, 'result': result}
> ```

***

## Accessing Context

Your code receives the workflow context and must return the updated context.

### JavaScript

```javascript theme={null}
// Context is available as 'context' variable
const policyNumber = context.policyNumber;
const claimant = context.claimant;

// Access nested properties
const firstName = context.claimant.firstName;

// Return updated context
return {
  ...context,  // Spread existing context (preserves all fields)
  newField: "new value"
};
```

### Python

```python theme={null}
# Context is available as 'context' dictionary
policy_number = context['policyNumber']
claimant = context['claimant']

# Access nested properties
first_name = context['claimant']['firstName']

# Return updated context
return {**context, 'newField': 'new value'}
```

> [!WARNING]
>
> Always return the full context object with your changes. If you only return new fields, you'll lose existing context data including system properties like `tenantId` and `environment`.

***

## Insurance Examples

### Calculate Days Since Loss

Determine how many days have passed since the incident and flag urgent claims.

> [tab] JavaScript
>
> ```javascript theme={null}
> const lossDate = new Date(context.dateOfLoss);
> const today = new Date();
>
> // Calculate difference in days
> const diffTime = Math.abs(today - lossDate);
> const daysSinceLoss = Math.floor(diffTime / (1000 * 60 * 60 * 24));
>
> // Determine urgency
> const isUrgent = daysSinceLoss <= 1;
> const priority = daysSinceLoss <= 1 ? 'high' : 
>                  daysSinceLoss <= 7 ? 'medium' : 'low';
>
> return {
>   ...context,
>   daysSinceLoss,
>   isUrgent,
>   priority
> };
> ```

> [tab] Python
>
> ```python theme={null}
> from datetime import datetime, date
>
> loss_date = datetime.strptime(context['dateOfLoss'], '%Y-%m-%d').date()
> today = date.today()
>
> # Calculate difference in days
> days_since_loss = (today - loss_date).days
>
> # Determine urgency
> is_urgent = days_since_loss <= 1
> if days_since_loss <= 1:
>     priority = 'high'
> elif days_since_loss <= 7:
>     priority = 'medium'
> else:
>     priority = 'low'
>
> return {
>     **context,
>     'daysSinceLoss': days_since_loss,
>     'isUrgent': is_urgent,
>     'priority': priority
> }
> ```

***

### Validate Policy Number Format

Check if a policy number matches expected patterns and extract components.

> [tab] JavaScript
>
> ```javascript theme={null}
> const policyNumber = context.policyNumber || '';
>
> // Define valid patterns
> const patterns = {
>   home: /^HO-\d{8}$/,
>   auto: /^AU-\d{8}$/,
>   commercial: /^CO-\d{8}$/
> };
>
> // Check which pattern matches
> let policyType = null;
> let isValid = false;
>
> for (const [type, pattern] of Object.entries(patterns)) {
>   if (pattern.test(policyNumber)) {
>     policyType = type;
>     isValid = true;
>     break;
>   }
> }
>
> // Extract components if valid
> let prefix = null;
> let number = null;
>
> if (isValid) {
>   const parts = policyNumber.split('-');
>   prefix = parts[0];
>   number = parts[1];
> }
>
> return {
>   ...context,
>   policyValidation: {
>     isValid,
>     policyType,
>     prefix,
>     number,
>     errorMessage: isValid ? null : 'Invalid policy number format'
>   }
> };
> ```

> [tab] Python
>
> ```python theme={null}
> import re
>
> policy_number = context.get('policyNumber', '')
>
> # Define valid patterns
> patterns = {
>     'home': r'^HO-\d{8}$',
>     'auto': r'^AU-\d{8}$',
>     'commercial': r'^CO-\d{8}$'
> }
>
> # Check which pattern matches
> policy_type = None
> is_valid = False
>
> for ptype, pattern in patterns.items():
>     if re.match(pattern, policy_number):
>         policy_type = ptype
>         is_valid = True
>         break
>
> # Extract components if valid
> prefix = None
> number = None
>
> if is_valid:
>     parts = policy_number.split('-')
>     prefix = parts[0]
>     number = parts[1]
>
> return {
>     **context,
>     'policyValidation': {
>         'isValid': is_valid,
>         'policyType': policy_type,
>         'prefix': prefix,
>         'number': number,
>         'errorMessage': None if is_valid else 'Invalid policy number format'
>     }
> }
> ```

***

### Calculate Claim Reserve Estimate

Estimate initial reserve based on claim type and details.

> [tab] JavaScript
>
> ```javascript theme={null}
> const claimType = context.claimType;
> const propertyType = context.propertyType || 'residential';
> const hasInjuries = context.injuriesReported || false;
>
> // Base reserve amounts by claim type
> const baseReserves = {
>   water: 5000,
>   fire: 25000,
>   theft: 3000,
>   auto: 8000,
>   wind: 10000,
>   liability: 15000
> };
>
> // Get base amount
> let reserve = baseReserves[claimType] || 5000;
>
> // Apply multipliers
> if (propertyType === 'commercial') {
>   reserve *= 2.5;
> }
>
> if (hasInjuries) {
>   reserve *= 3;
> }
>
> // Add complexity factor based on description length
> const descriptionLength = (context.claimDescription || '').length;
> if (descriptionLength > 500) {
>   reserve *= 1.25;  // Complex claims get higher reserve
> }
>
> return {
>   ...context,
>   reserveEstimate: {
>     amount: Math.round(reserve),
>     currency: 'USD',
>     factors: {
>       baseAmount: baseReserves[claimType] || 5000,
>       propertyMultiplier: propertyType === 'commercial' ? 2.5 : 1,
>       injuryMultiplier: hasInjuries ? 3 : 1,
>       complexityMultiplier: descriptionLength > 500 ? 1.25 : 1
>     },
>     requiresReview: reserve > 50000
>   }
> };
> ```

> [tab] Python
>
> ```python theme={null}
> claim_type = context.get('claimType')
> property_type = context.get('propertyType', 'residential')
> has_injuries = context.get('injuriesReported', False)
>
> # Base reserve amounts by claim type
> base_reserves = {
>     'water': 5000,
>     'fire': 25000,
>     'theft': 3000,
>     'auto': 8000,
>     'wind': 10000,
>     'liability': 15000
> }
>
> # Get base amount
> reserve = base_reserves.get(claim_type, 5000)
>
> # Apply multipliers
> if property_type == 'commercial':
>     reserve *= 2.5
>
> if has_injuries:
>     reserve *= 3
>
> # Add complexity factor based on description length
> description_length = len(context.get('claimDescription', ''))
> if description_length > 500:
>     reserve *= 1.25
>
> return {
>     **context,
>     'reserveEstimate': {
>         'amount': round(reserve),
>         'currency': 'USD',
>         'factors': {
>             'baseAmount': base_reserves.get(claim_type, 5000),
>             'propertyMultiplier': 2.5 if property_type == 'commercial' else 1,
>             'injuryMultiplier': 3 if has_injuries else 1,
>             'complexityMultiplier': 1.25 if description_length > 500 else 1
>         },
>         'requiresReview': reserve > 50000
>     }
> }
> ```

***

### Parse and Normalize Address

Clean up and standardize address components.

> [tab] JavaScript
>
> ```javascript theme={null}
> const rawAddress = context.propertyAddress || '';
>
> // State abbreviations mapping
> const stateAbbreviations = {
>   'california': 'CA', 'texas': 'TX', 'florida': 'FL',
>   'new york': 'NY', 'illinois': 'IL', 'pennsylvania': 'PA'
>   // Add more as needed
> };
>
> // Simple address parsing (for demo - use a library in production)
> const parts = rawAddress.split(',').map(p => p.trim());
>
> let street = parts[0] || null;
> let city = parts[1] || null;
> let stateZip = parts[2] || '';
>
> // Extract state and zip
> const stateZipMatch = stateZip.match(/([A-Za-z\s]+)\s*(\d{5}(-\d{4})?)?/);
> let state = stateZipMatch ? stateZipMatch[1].trim() : null;
> let zip = stateZipMatch ? stateZipMatch[2] : null;
>
> // Normalize state to abbreviation
> if (state) {
>   const stateLower = state.toLowerCase();
>   if (stateAbbreviations[stateLower]) {
>     state = stateAbbreviations[stateLower];
>   } else if (state.length === 2) {
>     state = state.toUpperCase();
>   }
> }
>
> return {
>   ...context,
>   normalizedAddress: {
>     street: street,
>     city: city,
>     state: state,
>     zip: zip,
>     formatted: [street, city, state, zip].filter(Boolean).join(', '),
>     isComplete: Boolean(street && city && state && zip)
>   }
> };
> ```

> [tab] Python
>
> ```python theme={null}
> import re
>
> raw_address = context.get('propertyAddress', '')
>
> # State abbreviations mapping
> state_abbreviations = {
>     'california': 'CA', 'texas': 'TX', 'florida': 'FL',
>     'new york': 'NY', 'illinois': 'IL', 'pennsylvania': 'PA'
>     # Add more as needed
> }
>
> # Simple address parsing
> parts = [p.strip() for p in raw_address.split(',')]
>
> street = parts[0] if len(parts) > 0 else None
> city = parts[1] if len(parts) > 1 else None
> state_zip = parts[2] if len(parts) > 2 else ''
>
> # Extract state and zip
> state_zip_match = re.match(r'([A-Za-z\s]+)\s*(\d{5}(-\d{4})?)?', state_zip)
> state = state_zip_match.group(1).strip() if state_zip_match else None
> zip_code = state_zip_match.group(2) if state_zip_match else None
>
> # Normalize state to abbreviation
> if state:
>     state_lower = state.lower()
>     if state_lower in state_abbreviations:
>         state = state_abbreviations[state_lower]
>     elif len(state) == 2:
>         state = state.upper()
>
> formatted_parts = [p for p in [street, city, state, zip_code] if p]
>
> return {
>     **context,
>     'normalizedAddress': {
>         'street': street,
>         'city': city,
>         'state': state,
>         'zip': zip_code,
>         'formatted': ', '.join(formatted_parts),
>         'isComplete': all([street, city, state, zip_code])
>     }
> }
> ```

***

### Process Multiple Line Items

Loop through an array of claim items and calculate totals.

> [tab] JavaScript
>
> ```javascript theme={null}
> const items = context.claimItems || [];
>
> // Process each item
> const processedItems = items.map((item, index) => {
>   const quantity = item.quantity || 1;
>   const unitPrice = item.unitPrice || 0;
>   const depreciation = item.ageYears ? (item.ageYears * 0.1) : 0;
>   const depreciationCapped = Math.min(depreciation, 0.7);  // Max 70% depreciation
>
>   const totalValue = quantity * unitPrice;
>   const depreciatedValue = totalValue * (1 - depreciationCapped);
>
>   return {
>     ...item,
>     lineNumber: index + 1,
>     totalValue: Math.round(totalValue * 100) / 100,
>     depreciatedValue: Math.round(depreciatedValue * 100) / 100,
>     depreciationPercent: Math.round(depreciationCapped * 100)
>   };
> });
>
> // Calculate totals
> const totalClaimValue = processedItems.reduce((sum, item) => sum + item.totalValue, 0);
> const totalDepreciatedValue = processedItems.reduce((sum, item) => sum + item.depreciatedValue, 0);
>
> return {
>   ...context,
>   processedItems,
>   claimSummary: {
>     itemCount: processedItems.length,
>     totalClaimValue: Math.round(totalClaimValue * 100) / 100,
>     totalDepreciatedValue: Math.round(totalDepreciatedValue * 100) / 100,
>     totalDepreciation: Math.round((totalClaimValue - totalDepreciatedValue) * 100) / 100
>   }
> };
> ```

> [tab] Python
>
> ```python theme={null}
> items = context.get('claimItems', [])
>
> processed_items = []
>
> for index, item in enumerate(items):
>     quantity = item.get('quantity', 1)
>     unit_price = item.get('unitPrice', 0)
>     age_years = item.get('ageYears', 0)
>
>     depreciation = age_years * 0.1 if age_years else 0
>     depreciation_capped = min(depreciation, 0.7)  # Max 70%
>
>     total_value = quantity * unit_price
>     depreciated_value = total_value * (1 - depreciation_capped)
>
>     processed_items.append({
>         **item,
>         'lineNumber': index + 1,
>         'totalValue': round(total_value, 2),
>         'depreciatedValue': round(depreciated_value, 2),
>         'depreciationPercent': round(depreciation_capped * 100)
>     })
>
> # Calculate totals
> total_claim_value = sum(item['totalValue'] for item in processed_items)
> total_depreciated_value = sum(item['depreciatedValue'] for item in processed_items)
>
> return {
>     **context,
>     'processedItems': processed_items,
>     'claimSummary': {
>         'itemCount': len(processed_items),
>         'totalClaimValue': round(total_claim_value, 2),
>         'totalDepreciatedValue': round(total_depreciated_value, 2),
>         'totalDepreciation': round(total_claim_value - total_depreciated_value, 2)
>     }
> }
> ```

***

## Error Handling

### Try-Catch Pattern

Wrap your code in try-catch to handle errors gracefully.

> [tab] JavaScript
>
> ```javascript theme={null}
> try {
>   // Your logic here
>   const result = someRiskyOperation(context.data);
>
>   return {
>     ...context,
>     result,
>     processingSuccess: true
>   };
> } catch (error) {
>   return {
>     ...context,
>     processingSuccess: false,
>     processingError: {
>       message: error.message,
>       type: error.name
>     }
>   };
> }
> ```

> [tab] Python
>
> ```python theme={null}
> try:
>     # Your logic here
>     result = some_risky_operation(context['data'])
>
>     return {
>         **context,
>         'result': result,
>         'processingSuccess': True
>     }
> except Exception as e:
>     return {
>         **context,
>         'processingSuccess': False,
>         'processingError': {
>             'message': str(e),
>             'type': type(e).__name__
>         }
>     }
> ```

### Branching After Code Node

Use the error flag in subsequent Decision Table or Mapping nodes:

```jsonata theme={null}
{
  "shouldContinue": $.processingSuccess = true,
  "errorMessage": $.processingSuccess ? null : $.processingError.message
}
```

***

## Best Practices

### Keep Code Focused

Each Code Node should do one thing well:

| ❌ Bad | ✅ Good |
| - | - |
| Validate AND calculate AND format | Code Node 1: Validate input |
| | Code Node 2: Calculate values |
| | Code Node 3: Format output |

### Use Descriptive Variable Names

```javascript theme={null}
// ❌ Bad
const x = context.a * 0.1;

// ✅ Good
const depreciationRate = context.ageYears * 0.1;
```

### Always Spread Context

Never return just your new fields:

```javascript theme={null}
// ❌ Bad - loses existing context
return { newField: value };

// ✅ Good - preserves existing context
return { ...context, newField: value };
```

### Handle Null/Undefined Values

```javascript theme={null}
// ❌ Bad - will throw if policyNumber is undefined
const prefix = context.policyNumber.substring(0, 2);

// ✅ Good - handles missing values
const policyNumber = context.policyNumber || '';
const prefix = policyNumber.substring(0, 2) || null;
```

### Add Comments for Complex Logic

```javascript theme={null}
// Calculate depreciation based on item age
// - 10% per year, capped at 70% maximum
// - Items over 7 years old use max depreciation
const depreciationRate = Math.min(context.ageYears * 0.1, 0.7);
```

### Test Edge Cases

Before deploying, test with:

* Empty strings and null values
* Empty arrays
* Missing nested properties
* Unexpected data types
* Boundary values (zero, negative numbers)

***

## Common Issues

### TypeError: Cannot Read Property of Undefined

**Symptom:** Code fails when accessing nested properties.

**Fix:** Use optional chaining or defensive checks:

```javascript theme={null}
// JavaScript
const city = context.address?.city || 'Unknown';

// Or
const city = context.address && context.address.city ? context.address.city : 'Unknown';
```

### Context Lost After Code Node

**Symptom:** System properties like `tenantId` are missing.

**Fix:** Always spread the original context:

```javascript theme={null}
return { ...context, newField: value };
```

### Infinite Loop

**Symptom:** Workflow times out in Code Node.

**Fix:** Add loop limits:

```javascript theme={null}
const MAX_ITERATIONS = 1000;
let count = 0;

while (condition && count < MAX_ITERATIONS) {
  // Your logic
  count++;
}
```

### Floating Point Precision

**Symptom:** Money calculations have weird decimals (e.g., `10.000000001`).

**Fix:** Round final values:

```javascript theme={null}
const total = Math.round(subtotal * 100) / 100;
```

***

## Next Steps

> [card] [Mapping Node](https://docs.liberate.ai/workflows/nodes/mapping-node.md)
>
> Use JSONata for simpler transformations

> [card] [Decision Table Node](https://docs.liberate.ai/workflows/nodes/decision-table-node.md)
>
> Route based on code output

> [card] [Task Node](https://docs.liberate.ai/workflows/nodes/task-node.md)
>
> Send processed data to external systems

> [card] [Workflow Examples](https://docs.liberate.ai/workflows/examples/fnol-workflow.md)
>
> See Code Node in complete workflows


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.