Fix NetSuite MODULE_DOES_NOT_EXIST in SuiteScript 2.x
NetSuite MODULE_DOES_NOT_EXIST SuiteScript 2.x error
Also searched as
- MODULE_DOES_NOT_EXIST Module does not exist NetSuite
- SuiteScript 2.1 define cannot find custom module path
- NetSuite script module not found after SDF deploy
- SuiteScript require relative path library not found
Short answer
MODULE_DOES_NOT_EXIST is thrown when the SuiteScript 2.x loader cannot resolve a path listed in define() or require(). In practice the cause is almost always a wrong relative path, a missing file in the File Cabinet, a bad N/ module name, or a library that was not deployed with the script.
Applies to: SuiteScript 2.0 and 2.1, all script types, File Cabinet and SDF (SuiteCloud Development Framework) deployments
How to fix MODULE_DOES_NOT_EXIST
- 1Read the full error message: it names the module string that failed to load, for example ./lib/utils or N/recrod. Copy that exact string.
- 2If it starts with N/, check spelling and case against the SuiteScript 2.x module list (N/record, N/search, N/runtime, N/query, N/https). N/ modules are case sensitive.
- 3If it is a relative path, open Documents > Files > File Cabinet and confirm the file exists at that path relative to the folder of the script that calls it.
- 4Check the file extension. NetSuite resolves ./utils to utils.js automatically, so do not include .js, and do not name the file utils.JS or utils.js.txt.
- 5Check the module's own header. A library loaded with define() must contain a define() call, not just plain functions, and must return its exports.
- 6In SDF projects, confirm the library file is under /SuiteScripts/ in the project and listed in deploy.xml or covered by the file import, then redeploy with suitecloud project:deploy.
- 7For paths starting with /SuiteScripts/, remember they are absolute from the File Cabinet root. A script moved to a different account folder keeps working only with absolute paths.
- 8Clear the cached script by saving the script record again (or redeploy), then rerun and read the Execution Log.
How the SuiteScript 2.x loader resolves a path
SuiteScript 2.x uses an AMD style loader. When your entry point script declares define(['N/record', './lib/helpers'], function(record, helpers){...}), NetSuite resolves each string at load time, before any of your code runs. N/ names map to built-in modules. Everything else is treated as a File Cabinet path.
A path beginning with ./ or ../ is relative to the folder of the file that contains the define call, not to the folder of the script record or the deployment. A path beginning with / is absolute from the File Cabinet root. This is why a script that works in /SuiteScripts/Sales/ breaks when the same file is copied into /SuiteScripts/Sales/v2/ without moving its libraries.
Because resolution happens at load, the error appears even if the missing module would only be used on a rare code path. The failure is reported against the entry point, which sometimes hides the fact that the broken define is in a library that the entry point loads in turn.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/record', './lib/helpers'], (record, helpers) => {
const afterSubmit = (ctx) => { helpers.log(ctx.newRecord.id); };
return { afterSubmit };
});Common causes seen in real accounts
The first group is typing. N/search misspelled as N/serach, N/Record with a capital R, or a path with a stray space. The second group is File Cabinet drift: a developer renames or moves a library folder through the UI, and every script that used a relative path to it breaks on the next load.
The third group is deployment. A SuiteApp or SDF project deploys the entry script but not the library because the library was never added to the project, or it sits in a folder excluded from the manifest. The sandbox works because someone uploaded the file by hand there, while production fails. Compare File Cabinet listings between sandbox and production.
The fourth group is a library that exists but does not define itself. If a file is a plain script with no define() wrapper, the loader finds the file but cannot treat it as a module. Some versions surface this as MODULE_DOES_NOT_EXIST with the path of the file, which confuses people who can plainly see the file in the cabinet.
Using path mappings and config files
For larger code bases, define a requirejs style configuration with the @NModuleScope and the config JSON referenced by the @NAmdConfig tag. A JSDoc line such as @NAmdConfig /SuiteScripts/config.json lets you give aliases to deep folders, so define(['lib/helpers']) resolves from one place.
If you use aliases, the MODULE_DOES_NOT_EXIST message will list the alias, not the final path. Check the paths object in the config and confirm the target is a folder or a file without extension. A common mistake is pointing an alias at a file with .js included.
Keep the config file in a stable location. If the config itself cannot be found, every module that depends on an alias fails, and the error looks widespread when it is a single bad path.
{
"paths": {
"lib": "/SuiteScripts/Common/lib"
}
}Debugging approach that saves time
Strip the define list to only N/ modules and run. If it loads, add custom modules back one at a time. This isolates the exact failing dependency in minutes instead of reading the whole stack. In Script Debugger, load the entry file directly; it reports module errors synchronously.
For SDF work, run suitecloud project:validate before deploy. It checks object references and some file dependencies and catches the library that was left out of the project. Add a CI step so library files are required to exist in the project directory tree.
Common pitfalls
- !Including .js in the define path: use ./lib/helpers, not ./lib/helpers.js.
- !Assuming relative paths are relative to the script record: they are relative to the file containing define().
- !Fixing the sandbox by uploading a file by hand and forgetting to add it to the SDF project.
- !Case differences between N/Record and N/record. Built-in module names are lowercase after the slash.
- !Moving a folder in the File Cabinet UI without searching for scripts that reference its files by absolute path.
- !A library with no define() wrapper, which loads as a file but is not a valid module.
How an ERP-grounded AI assistant handles this
An assistant grounded in your NetSuite code base can list every define() dependency in a script, compare it to the File Cabinet and SDF manifest, and tell you which referenced file is absent or misnamed before you deploy. ERPray is read-only by default, so it inspects metadata and file listings rather than editing scripts. A developer still reviews and deploys the fix.
Frequently asked questions
Why does it work in sandbox but fail in production?
The library file almost always exists in sandbox because it was uploaded manually or refreshed from an older production copy, but it was never part of the SDF project that deployed to production. Compare the File Cabinet folders in both accounts and add the missing file to the project.
Do I need the .js extension in define paths?
No. The loader appends .js for you. Including it causes the loader to look for a file named helpers.js.js and raises MODULE_DOES_NOT_EXIST. Use the bare path, relative or absolute, and keep the real file name ending in .js.
Is SuiteScript 2.1 different from 2.0 here?
Module resolution works the same way. The difference is the runtime: 2.1 supports modern JavaScript syntax. Mixed projects can fail if a 2.0 library is required from 2.1 code with a different NApiVersion tag, so keep tags consistent when you debug path errors.
Can a typo in an unused code path cause this?
Yes. Dependencies in define() are loaded eagerly when the script initialises, so a bad module string fails the whole script even if the function that uses it never runs. Remove or correct the entry rather than relying on the branch being skipped.
Related
Managing NetSuite sandbox refresh alongside SDF deployments
A NetSuite sandbox refresh clones production data and customization state into the sandbox account, which means any sandbox-only changes not captured in an SDF (SuiteCloud Development Framework) project are wiped, while changes that were already deployed to production survive because they come along with the refresh. Plan refreshes around your deployment calendar, and redeploy or validate your SDF project immediately after every refresh.
AdvancedSetting up a NetSuite SuiteCloud CI/CD pipeline
A repeatable NetSuite CI/CD pipeline uses SuiteCloud CLI for Node.js authenticated non-interactively with a Token-Based Authentication saved authentication ID, running suitecloud project:validate then project:deploy against a target account from a pipeline runner rather than a developer's machine. The main setup work is generating CI-specific TBA credentials, storing them as pipeline secrets, and keeping manifest.xml/deploy.xml accurate so deploys are deterministic.
AdvancedChoosing between User Event and Client scripts in NetSuite
User Event scripts (beforeLoad, beforeSubmit, afterSubmit) run server-side on every save regardless of how the record was created, including CSV import, web services and workflows, and are the only reliable place to enforce business rules. Client scripts (pageInit, fieldChanged, saveRecord, postSourcing) run only in an interactive browser session and can be bypassed entirely by any non-UI record save, so they should handle UX (field visibility, warnings, defaults) rather than validation that must never be skipped.
Error fixFix NetSuite SSS_MISSING_REQD_ARGUMENT Error
SSS_MISSING_REQD_ARGUMENT means a NetSuite API call, most often record.create(), record.load(), or search.create(), was called without a parameter that method requires, such as type or id. Fix it by checking the object literal you passed against the current SuiteScript 2.x API signature and confirming no required key is undefined at runtime.
Error fixFix NetSuite SSS_USAGE_LIMIT_EXCEEDED Error
SSS_USAGE_LIMIT_EXCEEDED fires when a SuiteScript execution consumes all the governance units (usage points) allotted to its script type before it finishes. Fix it by checking runtime.getCurrentScript().getRemainingUsage() before expensive calls, yielding or rescheduling in Scheduled scripts, and moving heavy record-count work into Map/Reduce, which yields automatically across stages.
Error fixFix NetSuite INVALID_FLD_VALUE Error
INVALID_FLD_VALUE means NetSuite rejected a value you tried to set on a field because it does not match the field's expected type, list option, or reference record. Fix it by confirming the internal ID or text value actually exists on that field's source list and matches the field's value type (text versus list versus record reference) before setting it.
AI for ERPAI for NetSuite, Beyond the Built-In Text Tools
NetSuite's built-in AI covers text generation, not grounded answers on your own data. See how a private LLM over SuiteQL adds real Q&A and controls.
Stuck on Oracle NetSuite?
Talk to engineers who work inside Oracle NetSuite every week, and who build private AI that answers these questions from your own ERP data.