NetSuite Integration Issues: Diagnose Silent Failures and Broken Syncs
NetSuite Integration Issues: Diagnose Silent Failures and Broken Syncs
When someone searches for NetSuite integration issues, they usually do not mean an abstract architecture problem. They mean orders stopped syncing. Fulfilments are missing. Duplicate customers appeared. A third-party system says the export succeeded, but NetSuite does not show the record.
Those failures are hard to fix because the first visible symptom is rarely the cause. A broken sync might be an expired token, a governance limit, a stuck scheduled task, bad idempotency, missing error handling, or a log that no longer contains the evidence you need.
The process below is the triage sequence I use for NetSuite integration rescue work. It starts with the symptom, then works down through NetSuite execution logs, RESTlet authentication, script governance, task queues, and logging.
Diagnosing a failure is one part of building integrations that last. The NetSuite integration guide covers the wider picture, from choosing an API to designing for failure.
Start with the symptom
Write down the exact business symptom before opening the script. It stops you chasing the wrong layer.
| Symptom | First place to check |
|---|---|
| Records stopped syncing into NetSuite | RESTlet execution log, integration auth, upstream retry logs |
| NetSuite created duplicate records | External ID mapping, idempotency keys, retry handling |
| A batch processed only some records | Governance usage, timeout errors, last successful log entry |
| Jobs sit for hours before running | Scheduled Script Status or Map/Reduce Script Status |
| The source system reports success but NetSuite is wrong | HTTP status handling, response parsing, reconciliation logic |
| The execution log is empty | Deployment status, trigger setup, RESTlet authentication |
Do not start by rewriting code. Start by proving which layer is failing.
Why NetSuite integrations fail silently
Before the diagnostic steps, it helps to understand the four main mechanisms that cause silent failure. Each requires a different place to look.
Governance exhaustion. Every SuiteScript execution context has a governance limit, a budget of "units" that API calls consume. A record.load() on a transaction costs 10 units; saving one costs 20. A User Event script has 1,000 units to work with, a Scheduled Script has 10,000, and Map/Reduce scripts get a separate budget per stage (10,000 for getInputData, 1,000 per map invocation, 5,000 per reduce invocation). When a script exceeds its budget, NetSuite throws SSS_USAGE_LIMIT_EXCEEDED and terminates the execution. That error appears in the execution log, but it is silent to the calling system and to anyone not actively checking that log: no error propagates to the caller, no alert fires by default, and a partial result looks the same as a complete one from the outside. If the script was halfway through processing a batch of records, the remaining records are skipped.
Token invalidation. RESTlet integrations use Token-Based Authentication (TBA), a consumer key/secret and token key/secret pair tied to an integration record and an employee record. TBA tokens do not expire on a schedule, and they deliberately survive password changes. They can still be invalidated: someone revokes the token, the integration record is blocked or deleted, the employee record is made inactive or deleted, or the role the token was issued against loses a required permission. When this happens, the RESTlet call returns an HTTP 401 with a body like {"error":{"code":"INVALID_LOGIN_ATTEMPT","message":"Invalid login attempt."}}. If the calling system checks the Content-Type header but not the HTTP status code, it treats the 401 body as data, fails to parse it as the expected response, and logs nothing useful.
Scheduled Script queue stalling. When you call task.create({taskType: task.TaskType.SCHEDULED_SCRIPT, ...}).submit() (or the old nlapiScheduleScript()), you are placing a task in a queue. That queue can stall. If the account has too many pending tasks, or if a previous execution of the same script is still running, the new task may sit in the queue with a status of PENDING. From the calling code's perspective, the submission succeeded. From the business perspective, nothing happened.
Log truncation. NetSuite retains script execution logs for 30 days, and anything older is gone. On a high-volume integration the volume itself becomes the problem: thousands of entries to page through, and under heavy load NetSuite can suppress debug-level entries. If the failure happened five weeks ago, or during a burst when the logger throttled, the evidence no longer exists.
Step 1: confirm it is actually running
The first question is whether the script is executing at all. This sounds obvious, but skipping it wastes time.
Go to Setup > Customization > Scripting > Scripts. Find the relevant script. Click on it, go to Deployments, and open the deployment record. Check:
- Status: is it set to "Released"? A deployment in "Testing" status only runs for administrators. A deployment accidentally set to "Not Scheduled" will not run at all.
- Event Type / Frequency: for Scheduled Scripts, is the schedule set correctly? A script set to "On Demand" will not run on a schedule.
- Execution Log tab: are there any recent entries? If the log is completely empty for a time period when you expected the script to run, the script is not running. The problem is the trigger, not the script logic.
For RESTlet integrations specifically, the execution log is populated on each inbound call. If you expect 100 calls per day and the log shows 3 entries, the calls are not reaching NetSuite. The problem is upstream: the calling system, the network, or the authentication.
Step 2: read the execution log correctly
Assuming the script is running, open the execution log. The columns that matter are Type, Title, and Details.
NetSuite log entries have four types: DEBUG, AUDIT, ERROR, and EMERGENCY. Your scripts should use log.debug() for routine checkpoints and log.error() for caught exceptions. If you see only AUDIT entries, which NetSuite itself writes for script start and stop events, and no DEBUG or ERROR entries, the script is running but the developer either did not add logging or the logging calls are never reached. That is useful diagnostic information.
Look for the last log entry before the execution stops. Compare it to the script source. If the last entry is "Processing record 493 of 800" and there is no "Completed" entry, the script died at record 493 or shortly after. The cause is probably governance exhaustion: a loop that loads and saves a transaction costs roughly 30 units per record (10 to load, 20 to save), so a Scheduled Script's 10,000-unit budget runs out around record 333, and the rest of the batch is skipped.
Governance and timeout failures look like this in the execution log:
Type: ERROR
Title: Script Execution Usage Limit Exceeded
Details: SSS_USAGE_LIMIT_EXCEEDEDor, for scripts that run out of wall-clock time rather than units:
Type: ERROR
Title: The script has exceeded the maximum execution time
Details: SSS_TIME_LIMIT_EXCEEDEDIf you see SSS_USAGE_LIMIT_EXCEEDED, the script tried to make an API call with fewer governance units remaining than the call costs. The solution is usually to restructure the script, often by converting a Scheduled Script to a Map/Reduce script, which handles batching natively and gives each reduce invocation its own governance allocation.
Step 3: check governance consumption explicitly
If you suspect governance exhaustion but the log does not show it clearly, add explicit governance logging to the script. The N/runtime module exposes the remaining governance units:
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
* @NModuleScope SameAccount
*/
define(['N/runtime', 'N/log'], (runtime, log) => {
const execute = (context) => {
log.debug('Governance at start', runtime.getCurrentScript().getRemainingUsage());
// ... processing loop ...
// Inside your loop, after each expensive call:
log.debug('Governance after record.load', runtime.getCurrentScript().getRemainingUsage());
};
return { execute };
});Adding this to an existing script and running it once tells you exactly how fast governance is being consumed. If you start with 10,000 units and you are down to 1,000 after 300 records, you will hit zero around record 333, and the log will show you where.
Step 4: verify authentication for RESTlet integrations
If the integration is inbound to a RESTlet, and the execution log shows no entries at all, the requests are not authenticating successfully.
The most reliable diagnostic is to make a test call from a tool like Postman or curl using the same credentials. A successful TBA-authenticated request to a RESTlet should return HTTP 200 with your RESTlet's JSON response. A failed authentication returns HTTP 401 with:
{
"error": {
"code": "INVALID_LOGIN_ATTEMPT",
"message": "Invalid login attempt."
}
}A common trap: this 401 response has the same Content-Type header as a successful response (application/json). Systems that check Content-Type but not the HTTP status code will parse this as valid JSON and then fail downstream when they try to access a field that does not exist.
To check the integration record itself: go to Setup > Integration > Manage Integrations. Find the integration. Look at whether TBA is enabled, and whether the token has been revoked. You cannot see the token value itself, because it is shown only once at creation, but you can revoke and reissue it. If you reissue and the integration starts working, expired or revoked credentials were the cause.
Step 5: check the task queue for Scheduled and Map/Reduce scripts
If your integration uses a Scheduled Script or Map/Reduce script triggered by another script via N/task, go to Customization > Scripting > Scheduled Script Status, or Map/Reduce Script Status for Map/Reduce scripts. These pages show submitted, processing, completed, and failed executions for the last 30 days.
Things to look for:
- A
Failedexecution with an error message.The script deployment is not scheduledmeans the deployment status was changed and the task could not find a valid execution target.RCRD_DSNT_EXISTmeans the task was created with a parameter pointing to a record that has since been deleted. - Submissions that throw at
task.submit()time because the same deployment is already running or no free deployment exists. If the calling script swallows that exception, the work is lost. - A long tail of
Pendingexecutions for the same deployment. The triggering logic is submitting tasks faster than the script can process them: every submission succeeds from the calling side, but the backlog grows and processing falls hours or days behind.
The backlog case is worth calling out because it looks like success everywhere you would normally check. The status page is the only place it is visible unless the integration already writes its own heartbeat record or queue-depth metric. Treat an expected run that never happened as a failure, even when NetSuite never throws an error.
Step 6: look for upstream truncation
If the log shows what looks like successful processing but the data still is not right, consider that the log you are reading may be incomplete. To verify this, look at the entry count. The execution log page does not show a total count by default, but if you see entries with timestamps that have a gap, such as 3:01pm then 3:47pm with nothing in between for a script that runs every minute, entries were dropped.
The mitigation is to write critical checkpoints as log.audit() rather than log.debug(). Audit entries are what NetSuite itself uses for script lifecycle events, and they are not suppressed the way high-frequency debug entries can be. For high-volume integrations, consider writing a separate audit trail to a custom record (N/record.create() with a small custom record type), which gives you persistent, queryable logging that outlives the 30-day execution log retention.
The order of checks
To summarise the diagnostic sequence:
- Confirm the script deployment is active and correctly configured.
- Check whether the execution log has any entries at all. If not, the script is not running, so find the trigger problem.
- Find the last log entry in a failed run. What was the script doing immediately before it stopped?
- Look for
SSS_USAGE_LIMIT_EXCEEDEDorSSS_TIME_LIMIT_EXCEEDEDin the log. If present, governance or time exhaustion is the cause. - For RESTlet integrations with no log entries: make a manual test call to verify authentication. Check the integration record.
- For queue-based scripts: check the Scheduled Script Status or Map/Reduce Script Status page for failed executions or a growing backlog.
- If the log looks clean but data is wrong: suspect truncation. Look for timestamp gaps and consider whether the log represents all executions.
Need to find why a NetSuite integration is failing?
I can trace whether the issue is governance, authentication, queue backlog, missing logging, duplicate handling, or integration design.
Book an integration failure triageNot ready to book? Send the symptom and I'll tell you whether it sounds like work I can help with.
Silent failures are diagnosable. They just require knowing where to look, and in what order. If you need someone to work through the diagnostic sequence with you, book an integration failure triage.
If you have a NetSuite integration that has stopped working and you cannot pin down why, that is exactly the kind of problem I work on. Book an integration failure triage and we can work through the evidence.
Frequently asked questions
How do I fix NetSuite integration issues?
Start by separating the symptom from the cause. Check whether requests are reaching NetSuite, whether the execution log has recent entries, whether a RESTlet returns HTTP 401, whether the script is hitting SSS_USAGE_LIMIT_EXCEEDED, and whether Scheduled Script or Map/Reduce jobs are stuck in Pending. Once you know which layer is failing, the fix is much smaller and safer.
Why do NetSuite integrations fail without throwing any errors?
The four main mechanisms are governance exhaustion (the script hits its unit limit and NetSuite terminates it silently mid-run), token invalidation (the calling system receives an HTTP 401 but does not check the status code, so the error response is mistaken for data), scheduled script queue stalling (the task is submitted successfully but sits in a Pending state indefinitely), and log truncation (NetSuite only retains execution logs for 30 days, and under heavy load it suppresses debug entries entirely).
How do I tell if governance exhaustion is causing my SuiteScript to stop mid-run?
Look in the execution log for SSS_USAGE_LIMIT_EXCEEDED or SSS_TIME_LIMIT_EXCEEDED. If the log ends abruptly with no completion entry, add runtime.getCurrentScript().getRemainingUsage() calls inside your processing loop via the N/runtime module. This shows exactly how fast governance units are being consumed and at which record the budget runs out. The fix is usually converting a Scheduled Script to Map/Reduce, which gives each reduce invocation its own governance allocation.
My RESTlet integration stopped working and the execution log is empty. What should I check?
An empty execution log for an inbound RESTlet means the requests are not reaching NetSuite, which is almost always an authentication failure. Make a test call using Postman or curl with the same TBA credentials. A failed authentication returns HTTP 401 with an INVALID_LOGIN_ATTEMPT error body. Then check Setup > Integration > Manage Integrations to confirm the integration record is active and TBA is still enabled. If the token was revoked, you can reissue it from Setup > Users/Roles > Access Tokens.
How long does NetSuite keep script execution logs?
30 days. Anything older is gone permanently. On high-volume integrations, debug-level entries can also be suppressed under load before the 30-day limit. Write critical checkpoints as log.audit() rather than log.debug(), since audit entries are not suppressed. For anything you need to keep longer than 30 days, write to a custom record using N/record.create(). This gives you queryable, persistent logging that outlives the execution log.
Need to find why a NetSuite integration is failing?
I can trace whether the issue is governance, authentication, queue backlog, missing logging, duplicate handling, or integration design.
Book an integration failure triage