Error fixOracle NetSuiteRecord Concurrency / SuiteScript

Fix NetSuite RCRD_HAS_BEEN_CHANGED Error

Error
The record you are trying to edit has been changed by another user NetSuite

Also searched as

  • RCRD_HAS_BEEN_CHANGED NetSuite error
  • NetSuite record has been changed by another user or in another window
  • NetSuite concurrent edit conflict SuiteScript

Short answer

RCRD_HAS_BEEN_CHANGED, shown to users as a message that the record was changed by another user or in another window, fires when NetSuite's optimistic concurrency check detects that the record's last-modified stamp changed between when it was loaded and when the save was submitted. Fix it by identifying the concurrent writer, whether a user, a workflow, or a script, and serializing the conflicting updates instead of both racing to save the same record.

Applies to: NetSuite UI record editing and SuiteScript 1.0/2.x record.save(), all record types

How to fix RCRD_HAS_BEEN_CHANGED

  1. 1In the UI, the fix is simply to refresh the record and reapply your edit; the error itself is NetSuite protecting you from overwriting someone else's save.
  2. 2In SuiteScript, check whether the same record is being loaded and saved by more than one script (a User Event and a Scheduled Script, or two Map/Reduce reduce keys) at nearly the same time.
  3. 3Search Customization > Scripting > Script Deployments for every script deployed on the record type in question and check which ones run on the same trigger, since simultaneous afterSubmit executions on one record are the most frequent self-inflicted cause.
  4. 4If two of your own scripts are colliding, consolidate the logic into a single script or use the Execution Context and Sequence fields on the deployment record to control order.
  5. 5For Map/Reduce jobs that update a shared parent record from multiple reduce keys, reduce the granularity so only one reduce invocation touches a given parent record, or add retry logic with record.load() immediately before each save.
  6. 6Add try/catch around record.save() with a short retry (reload, reapply the one field you need, save again) for scripts that legitimately may race with user edits, capped at two or three attempts to avoid infinite loops.
  7. 7For integration-driven high-frequency updates, such as a webhook updating order status, queue updates to the same record instead of firing them concurrently from multiple threads.

What optimistic concurrency means here

NetSuite does not lock records for editing the way some legacy client-server ERPs do. Instead it uses optimistic concurrency: when a record is loaded, NetSuite notes its last-modified state, and when a save is submitted it checks that state has not changed since. If it has, the save is rejected with RCRD_HAS_BEEN_CHANGED rather than silently overwriting the other change.

This is a safety feature, not a bug, but it becomes a real operational problem when it fires between two automated processes that should never conflict in the first place, for example a nightly integration and a Scheduled Script both trying to update the same batch of records.

Diagnosing script-versus-script races

The most common source in scripted environments is two afterSubmit User Event scripts on the same record type, both loading and saving the record independently in response to the same edit. Because both start from the pre-edit state, whichever saves second gets RCRD_HAS_BEEN_CHANGED against the first script's save.

List every script deployment on the record type (Customization > Scripting > Script Deployments, filter by record type) and check the Execution Context and event type columns for overlaps. Consolidating two afterSubmit scripts that both call record.load() plus save() into a single script that makes both changes in one save eliminates the race entirely.

Handling legitimate concurrent access

When the conflict is between a genuine user edit and a background process, not two of your own scripts, the correct fix is not to force the save through but to retry against the freshest version of the record. Load the record again immediately before the retry, reapply only the specific field your process needs to change, and save.

Cap retries at two or three attempts with a short delay, and log a warning rather than silently swallowing the failure after max retries, since repeated collisions usually indicate a design issue, too many processes touching one record, rather than bad luck.

var attempts = 0;
while (attempts < 3) {
  try {
    var rec = record.load({ type: type, id: id });
    rec.setValue({ fieldId: 'custbody_status', value: 'done' });
    rec.save();
    break;
  } catch (e) {
    if (e.name !== 'RCRD_HAS_BEEN_CHANGED') { throw e; }
    attempts++;
  }
}

Common pitfalls

  • !Two of your own afterSubmit scripts both loading and saving the same record independently instead of consolidating logic into one script.
  • !Map/Reduce jobs where multiple reduce invocations update the same parent record concurrently.
  • !Integration webhooks firing updates to the same record in parallel instead of queued or serialized.
  • !Retrying a save in a loop without reloading the record first, which just repeats the same collision.
  • !Treating this as a random glitch instead of tracing the actual concurrent writer, which almost always exists and is findable.

How an ERP-grounded AI assistant handles this

Grounded on your script deployment configuration, ERPray can list every script and workflow action attached to a record type and flag the ones most likely to race against each other on the same trigger, which is the manual detective work this error usually requires. For recurring conflicts on specific record types, you can ask it to summarize which processes touched a given record in the minutes before a failed save, using your account's system notes as grounding.

Frequently asked questions

Does this mean I lost my data when I see this error?

No, NetSuite blocks the save specifically to prevent silent data loss. Your edit was never committed; you need to refresh to the current version of the record and reapply your change.

Can I disable this concurrency check?

No, there is no supported way to disable NetSuite's optimistic concurrency check; it is a platform-level protection. The correct approach is to eliminate or serialize the actual conflicting writers.

Why does this happen more often on Map/Reduce jobs?

Because Map/Reduce distributes work across parallel reduce invocations. If your reduce function's key grouping allows two invocations to both update the same parent or related record, they race against each other exactly like two independent scripts would.

Is this related to record locking permissions?

No, it is unrelated to role permissions or record locking settings. It is purely a timestamp-based concurrency check that fires regardless of what role or script is doing the saving.

Related

Error fix

Fix 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 fix

Fix NetSuite INSUFFICIENT_PERMISSION Error

INSUFFICIENT_PERMISSION means the role executing the request, whether a logged-in user or the role behind a script deployment, lacks a specific permission needed for the record type, transaction type, or subsidiary being accessed. Fix it by checking the role's permission list under Setup > Users/Roles > Manage Roles against the exact record and level (View, Create, Edit, or Full) the operation requires.

Error fix

Fix 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.

Error fix

Fix 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.

How-to

How to use formula fields in a NetSuite saved search

In the saved search Results tab, add a column, set Field to "Formula (Text)", "Formula (Numeric)", "Formula (Date)" or "Formula (Currency)", then type an Oracle SQL expression into the Formula box using curly braces around field IDs, e.g. {trandate} or {item.custitem_weight}. Formula fields can also go on the Criteria tab so you can filter on the calculated value itself.

How-to

How to write and run SuiteQL queries in NetSuite

SuiteQL is NetSuite's read-only SQL dialect over the underlying record tables, run either interactively from Analytics > SuiteQL Query Tool (or the older /app/suiteanalytics query page), through REST at /services/rest/query/v1/suiteql, or programmatically via the N/query module in SuiteScript 2.x. It supports standard SELECT, JOIN, WHERE, GROUP BY and window functions against table names that mostly match record type IDs (transaction, transactionline, item, customer).

AI for ERP

AI 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.