Fixing “(intermediate value).warn is not a function” in SuiteScript
One of the more misleading errors in NetSuite. It looks like a logging problem. It isn't.
A Map/Reduce script that had been running quietly for months started filling the execution log. Several hundred errors in a single day, all identical:
TypeError: (intermediate value).warn is not a function
Nothing about the logging had changed. The line it pointed to was an ordinary log.warn call that had been in the script since it was written.
What the error actually means
Read it literally. JavaScript is telling you that the thing to the left of .warn is not a function — it evaluated log, got back something, and that something has no warn method on it.
So log is not the logging module. It's bound to something else entirely.
In SuiteScript 2.x, your module dependencies are declared as an array, and the callback receives them as positional parameters:
define(['N/record', 'N/search', 'N/runtime'],
function (record, search, runtime) {
// ...
});
The binding is positional, not by name. NetSuite hands you the first module as the first parameter, the second as the second, and so on. It never checks whether the names you chose make sense.
Which means a signature like this compiles and deploys without complaint:
define(['N/record', 'N/search', 'N/runtime'],
function (record, search, runtime, log) {
log.warn('something', details); // throws
});
Four parameters, three modules. The fourth parameter, log, is undefined — and because you declared it in the signature, it shadows the implicit global log object that would otherwise have worked fine.
The variant that produces the exact "is not a function" wording rather than a null-reference error is subtler: the array and the parameters are the same length, but out of order. log gets bound to a real module — just not the logging one. It's an object, so accessing .warn doesn't fail; calling it does.
The fix
Add N/log to the array, in the position matching your parameter:
define(['N/record', 'N/search', 'N/runtime', 'N/log'],
function (record, search, runtime, log) {
log.warn('something', details); // works
});
Then count them. Array length must equal parameter count, and the order must match exactly. This is worth doing by eye on every script in the file — if one is misaligned, others written the same day usually are too.
Why it appears out of nowhere
This is the part that wastes the afternoon. The script deployed fine, ran for months, and then started failing — with no deployment in between.
The reason is that the broken line was never reached. log.warn calls typically sit inside error handlers and edge-case branches. The script ran happily until the day a record finally hit that branch, and then the logging call itself became the error — masking whatever condition actually triggered it.
So you get two problems at once: a misaligned dependency, and a hidden data condition you now can't see, because the code that was supposed to tell you about it is the code that's throwing.
Preventing it
- Keep the module array and the parameter list on adjacent lines so a mismatch is visible at a glance.
- Never name a callback parameter
logunlessN/logis in the array — the implicit global works fine on its own, and shadowing it is how this starts. - Exercise your error paths in Sandbox. A logging call inside a branch nothing has hit yet is untested code.
- When triaging the execution log, sort by frequency first. Hundreds of identical errors in one day is nearly always a single small defect, not hundreds of problems.