Book a call
Home  /  Insights  /  SuiteScript

Why your Map/Reduce keeps hitting SSS_USAGE_LIMIT_EXCEEDED

The error names the script, not the line that spent the units. Here is how to find the real culprit, and the four swaps that usually fix it.

A
Atsovia NetSuite team
18 September 2026 · 9 min read

The message is unhelpful in a specific way. SSS_USAGE_LIMIT_EXCEEDED tells you a stage ran out of units. It does not tell you which call spent them, and in a Map/Reduce the stage that fails is often not the stage doing the expensive thing.

Here is how to find the real culprit, and the four swaps that fix the large majority of cases.

First: which budget did you actually blow

Map/Reduce does not have one limit. It has four, one per stage, and they are very different sizes. A script that is comfortable in getInputData can be nowhere near comfortable in map, because map gets a tenth of the budget.

Stage
Units
Time
Runs
getInputData
10,000
60 min
Once
map
1,000
5 min
Per key
reduce
5,000
15 min
Per key
summarize
10,000
60 min
Once

Read the fourth column again, because it is the one people skip. The map budget is not 1,000 units for your whole script, it is 1,000 units per key, refreshed on every invocation. That is the entire point of the architecture, and it is why moving work from a Scheduled script into map is so often the fix rather than the problem.

There is also a soft limit of 10,000 units per job. Crossing it does not throw; the job yields gracefully and a new one picks up where it left off. So if your script is finishing but taking far longer than you expected, you are probably yielding repeatedly, which is a performance problem wearing a governance costume.

Second: measure, do not guess

Every governance conversation should start with a number. Two lines get you one:

define(['N/runtime'], (runtime) => {

const spent = (label, before) => {
const now = runtime.getCurrentScript().getRemainingUsage();
log.audit('governance', label + ': ' + (before - now) + ' units, ' + now + ' left');
return now;
};

const map = (ctx) => {
let u = runtime.getCurrentScript().getRemainingUsage();
const rec = record.load({ type: 'salesorder', id: ctx.key });
u = spent('load', u);
// ... the rest of the work, each block measured the same way
};
});
Wrap each block, then read the audit log. The expensive line is always obvious once it is printed.

Nine times out of ten the log shows something nobody expected: a lookup inside a loop, a record loaded to read one field, a search re-run per iteration. Governance bugs are rarely clever. They are almost always a cheap call placed inside something that repeats.

The limit is not the problem. The loop around the call is the problem.

The four swaps

1. Stop loading records you only want to read. A record.load on a transaction costs 10 units. search.lookupFields costs 1, and returns as many fields as you ask for. If you are loading a record to read three fields and never calling save, you are paying ten times the price for nothing. On 80 records that single swap is 720 units back.

2. Stop loading records you only want to write. The mirror image. record.load plus record.save on a transaction is 30 units. record.submitFields writes body fields for 10 and skips the load entirely. It will not touch sublines, so it is not a universal replacement, but for status flags, custom body fields and date stamps it is strictly better.

3. Move paged searches to SuiteQL. A saved search costs 10 units per page of results. query.run costs 10 for the result set. On one page they tie; on ten pages the search costs 100 and the query still costs 10. If you are iterating more than a couple of thousand rows, this is usually the biggest single line item in the log.

4. Rebalance the keys. If map is blowing its budget, the honest reading is that each key is carrying too much work. Emit finer keys from getInputData so more invocations each do less, or push the heavy per-record work into reduce, where the budget is five times larger and the time limit three times longer.

The one that is not a swap

If the work genuinely cannot be made cheaper, stop trying to fit it into one execution. Yield After Minutes is configurable from 3 to 60, and a script that yields deliberately is far healthier than one that fails at 94% complete and leaves you reconciling half-processed records on a Monday morning.

What this looks like in practice

The version of this we see most often: a Map/Reduce that reconciles fulfilments. getInputData returns a search of open orders. map loads each order, loads the related item fulfilment, reads four fields from each, and writes a status back. That is 10 + 10 for the loads, 20 for the save, plus a search inside the loop.

Rewritten: a SuiteQL query in getInputData returns the order and fulfilment fields together, so map receives everything it needs in the key value and never loads anything. The write becomes a submitFields. The per-key cost falls from roughly 55 units to 10, and the script stops being the thing that wakes somebody up.

None of that is clever. It is just paying attention to what each call costs, which is why we built a calculator that shows it rather than writing another article about it.

Try it against your own script

SuiteScript governance calculator

Add your operations, pick the script type, and see the total against the limit, plus which call to swap out first.

Open the calculator
A
Atsovia NetSuite team
Implementation and development

Years of building on NetSuite: SuiteScript, SuiteFlow, SuiteQL, SuiteTalk, Advanced PDF templates and Celigo integrations. We write these up when a problem comes round for the third time.

More about the team → Get in touch →

Keep reading

Administration
Cutting NetSuite file cabinet costs without deleting anything
7 min read
SuiteQL
SuiteQL or saved search: how to decide, with the governance maths
11 min read
Manufacturing
Work-order scrap: capturing it where it actually happens
8 min read
Next step

Book a free consultation

Tell us what you are running today and where it is breaking down. Most calls run 20 to 30 minutes and end with a clear next step. We reply within one business day.

Talk to a consultant