๐งฉ Custom Error Handling & Retry Framework for SuiteScript Integrations
Introduction
Even the best-written NetSuite integrations fail occasionally โ APIs time out, governance limits hit, or third-party services go down.
Instead of manually checking logs, you can build a Custom Error Handling Framework that captures every failure, logs it, and automatically retries based on rules.
This tutorial will walk you through creating a robust, reusable error-handling layer used in real-world integrations with Boomi, Shopify, and Salesforce.
๐ก Why a Centralized Error Framework?
Problem | Without Framework | With Framework |
---|---|---|
API timeouts | Manual debugging | Auto-retry with delay |
Script failures | Lost transaction data | Logged & queued for re-execution |
Governance limits | Script halts | Automatically resumes from checkpoint |
Lack of visibility | Hard to trace | Central error dashboard |
๐งฑ Step 1: Create Custom Record โ โIntegration Error Logโ
Name: Integration Error Log
ID: customrecord_error_log
Field Label | ID | Type | Description |
---|---|---|---|
Integration Source | custrecord_err_source | Text/List | Boomi, Celigo, RESTlet |
Record Type | custrecord_err_recordtype | Text/List | Sales Order, Invoice |
Record ID | custrecord_err_recordid | Integer | Failed record reference |
Error Message | custrecord_err_message | Long Text | Full stack trace |
Retry Status | custrecord_err_retry_status | List (Pending, Retried, Failed) | Current retry status |
Retry Count | custrecord_err_retry_count | Integer | Number of attempts |
Timestamp | custrecord_err_timestamp | Date/Time | When the error occurred |
Script Type | custrecord_err_script_type | Text | e.g., Map/Reduce, RESTlet |
Process ID | custrecord_err_processid | Text | Unique run identifier |
โ Add permissions for Integration Admin or Developer roles only.
โ๏ธ Step 2: Centralized Error Handling Utility
Create a shared module you can import into any SuiteScript.
/**
* @NApiVersion 2.1
* @NModuleScope Public
*/
define(['N/record', 'N/log'], (record, log) => {
const logError = (source, recordType, recordId, errorObj, scriptType) => {
try {
const errRec = record.create({ type: 'customrecord_error_log', isDynamic: true });
errRec.setValue('custrecord_err_source', source);
errRec.setValue('custrecord_err_recordtype', recordType);
errRec.setValue('custrecord_err_recordid', recordId);
errRec.setValue('custrecord_err_message', JSON.stringify(errorObj.message || errorObj));
errRec.setValue('custrecord_err_retry_status', 'Pending');
errRec.setValue('custrecord_err_retry_count', 0);
errRec.setValue('custrecord_err_script_type', scriptType);
errRec.save();
} catch (e) {
log.error('Error Logging Failure', e);
}
};
return { logError };
});
โ Usage: Import this module into any Map/Reduce, RESTlet, or Scheduled Script to catch and record errors.
๐ง Step 3: Add Try/Catch Blocks with Error Logging
Example in a Map/Reduce Script:
try {
// process invoice
record.submitFields({ type: 'invoice', id: invId, values: { memo: 'Processed' } });
} catch (e) {
errorHandler.logError('Boomi', 'invoice', invId, e, 'Map/Reduce');
}
Every exception is automatically logged to your Integration Error Log.
๐ Step 4: Automated Retry Script
Create a Scheduled Script or Map/Reduce to re-process failed records.
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
*/
define(['N/search', 'N/record', 'N/log'], (search, record, log) => {
const execute = () => {
const results = search.create({
type: 'customrecord_error_log',
filters: [['custrecord_err_retry_status', 'is', 'Pending'], 'AND', ['custrecord_err_retry_count', 'lessthan', 3]],
columns: ['internalid', 'custrecord_err_recordid', 'custrecord_err_source']
}).run().getRange({ start: 0, end: 50 });
results.forEach(r => {
try {
const recordId = r.getValue('custrecord_err_recordid');
// Retry logic (e.g., re-call RESTlet or re-process transaction)
log.audit('Retrying Record', recordId);
record.submitFields({
type: 'salesorder',
id: recordId,
values: { custbody_retry_flag: true }
});
record.submitFields({
type: 'customrecord_error_log',
id: r.id,
values: {
custrecord_err_retry_status: 'Retried',
custrecord_err_retry_count: '@{custrecord_err_retry_count}+1'
}
});
} catch (err) {
log.error('Retry Failed', err);
}
});
};
return { execute };
});
โ Retries only failed records with retry count < 3 โ prevents infinite loops.
๐งฎ Step 5: Dashboard Monitoring (Saved Search or SuiteAnalytics)
Saved Search: Integration Error Overview
- Filters:
custrecord_err_retry_status is not Success
- Columns: Source, Record Type, Record ID, Error Message, Retry Count, Last Update
- Highlighting:
- Red โ Failed
- Yellow โ Pending
- Green โ Retried
Add this to Home Dashboard for real-time tracking.
๐ง Step 6: Email / Slack Notifications
Workflow Notification (Simpler)
- Trigger: On Create (if Retry Status = โPendingโ)
- Action: Send Email โ Integration Team
Advanced (Slack via RESTlet)
Send Slack alert on every failed integration:
https.post({
url: 'https://hooks.slack.com/services/T0000/B0000/XXXX',
body: JSON.stringify({ text: `๐จ Integration Failed: ${errorMessage}` }),
headers: { 'Content-Type': 'application/json' }
});
โก Step 7: Governance & Performance Tips
Challenge | Solution |
---|---|
Too many logs | Auto-delete records older than 90 days via Scheduled Script |
Long stack traces | Store JSON payloads in File Cabinet |
Concurrent retries | Use Map/Reduce for batch retry |
High volume | Split logs by integration source |
๐งฉ Real-World Framework Workflow
1๏ธโฃ RESTlet / Script fails โ Logs error in Custom Record
2๏ธโฃ Scheduled Script scans Pending logs daily
3๏ธโฃ Retries failed transactions (up to 3ร)
4๏ธโฃ Success โ Status = Retried; Failure โ Status = Failed
5๏ธโฃ Dashboard + Email Alerts show live summary
๐งฐ Bonus: Custom Error Utility Snippet
Reusable utility for cleaner scripts:
function safeExecute(fn) {
try { fn(); }
catch (e) { errorHandler.logError('RESTlet', 'transaction', null, e, 'Suitelet'); }
}
โ Keeps your core code readable and error-proof.
๐ Related Tutorials
- ๐ Integration Logging & Monitoring Dashboard
- ๐ SuiteScript Security & Governance Best Practices
- ๐ NetSuite Deployment & Version Control Strategy
โ FAQ
Q1. Can I automatically retry failed Boomi or Celigo integrations?
Yes โ send retry POST requests from the Scheduled Script back to your middleware endpoint.
Q2. Can this handle RESTlet and Map/Reduce together?
Absolutely โ log script type (Map/Reduce
, RESTlet
) and handle retries differently per type.
Q3. Can I notify users in NetSuite UI?
Yes โ use a custom Portlet showing recent โFailed Integrations.โ
Q4. What if error logging itself fails?
Wrap the logger in a try/catch with minimal dependencies (as above) so failure doesnโt block your main process.
๐งญ Summary
With this framework, your NetSuite environment gains self-healing capability โ failed transactions are captured, reviewed, and retried automatically.
Instead of reactive debugging, you get proactive stability, visibility, and accountability for every integration.
This pattern transforms NetSuite into an enterprise-grade integration platform ready for high-volume, audit-safe operations.
Leave a Reply