SSS_TIME_LIMIT_EXCEEDED: You have exceeded the maximum execution time for this script type.Quick Reference
- Error Code
- SSS_TIME_LIMIT_EXCEEDED
- Severity
- high
- Type
- script
- Versions
- 2024.1, 2024.2, 2025.1, 2025.2, 2026.1
Why This Happens
- Client Script or User Event Script performing expensive operations synchronously (HTTP calls, large searches)
- Scheduled Script processing too many records without yielding — the 60-minute wall clock limit is absolute
- Suitelet or RESTlet making multiple external HTTP calls that each take seconds to respond
- Unoptimized saved search with too many results or complex formulas running at script start
- Recursive or deeply nested logic that scales exponentially with input size
How to Fix It
Step 1: Identify the slow operation
Add log.debug timestamps before and after each major operation. Look for https.get/post calls, record.load on large records (e.g., Sales Orders with 1000+ lines), and search.run on unfiltered searches. The SuiteScript Profiler in NetSuite (Customization > Scripting > Script Execution Log) also shows per-execution timing.
Step 2: Move heavy work to async script types
User Event and Client Scripts have strict time limits (30 seconds for beforeSubmit, 45 seconds for afterSubmit). If you need to process data after a record save, trigger a Map/Reduce or Scheduled Script from afterSubmit using task.create instead of doing the work inline.
Step 3: Paginate and checkpoint
For Scheduled Scripts, implement the same governance checkpoint pattern used for SSS_USAGE_LIMIT_EXCEEDED — check remaining time or governance, save your position, and reschedule. Map/Reduce handles this automatically through its map() and reduce() stages.
Step 4: Optimize external HTTP calls
If calling external APIs, use https.request with timeout settings. Batch multiple requests where the external API supports it. Cache responses in a custom record or script parameter if the data doesn't change frequently.
Code Example
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*
* Pattern: offload heavy work from afterSubmit to a Map/Reduce script.
* This prevents SSS_TIME_LIMIT_EXCEEDED on the User Event.
*/
define(['N/task', 'N/runtime', 'N/log'], (task, runtime, log) => {
function afterSubmit(context) {
if (context.type !== context.UserEventType.CREATE &&
context.type !== context.UserEventType.EDIT) {
return;
}
try {
const mrTask = task.create({
taskType: task.TaskType.MAP_REDUCE,
scriptId: 'customscript_process_order_mr',
deploymentId: 'customdeploy_process_order_mr',
params: {
custscript_order_id: context.newRecord.id
}
});
const taskId = mrTask.submit();
log.audit('Task submitted', `Map/Reduce task ${taskId} for record ${context.newRecord.id}`);
} catch (e) {
// Don't throw — afterSubmit errors don't roll back the record save,
// but they do show an error banner to the user.
log.error('Failed to submit MR task', e.message);
}
}
return { afterSubmit };
});Common Mistakes
- Putting synchronous HTTP calls in beforeSubmit — this blocks the user's save action and has a 30-second hard limit
- Running a saved search with no filters in a User Event — a search returning 10,000 results takes several seconds even if you only need the first 10
- Not setting a timeout on https.get/post calls — a single slow external API can consume the entire script time budget
- Assuming Map/Reduce is immune to time limits — each individual map() call has a 60-minute limit, and getInputData has a 1-hour limit
Alternative Approaches
- Use N/task to trigger asynchronous processing from User Events instead of doing work inline
- For Suitelets that generate large reports, stream results with response.writePage() instead of building the entire response in memory
- Consider SuiteQL for complex queries — it often executes 2-5x faster than equivalent saved searches