RCRD_DSNT_EXIST: That record does not exist.Quick Reference
- Error Code
- RCRD_DSNT_EXIST
- Severity
- medium
- Type
- record
- Versions
- 2024.1, 2024.2, 2025.1, 2025.2, 2026.1
Why This Happens
- The internal ID is wrong — it was hardcoded, came from stale data, or was parsed incorrectly (string vs number)
- The record was deleted between the time you got the ID and the time you tried to load it
- Subsidiary restriction — in OneWorld, the role doesn't have access to the subsidiary that owns this record
- Record type mismatch — trying to load a record with the wrong type (e.g., loading internal ID 123 as SALES_ORDER when it's actually an INVOICE)
- The record exists but in a different environment (production vs sandbox) — IDs don't transfer between environments
How to Fix It
Step 1: Verify the record exists in the UI
Go to the record URL directly: /app/common/entity/entity.nl?id=123 (for entities) or /app/accounting/transactions/transaction.nl?id=123 (for transactions). Replace with the correct record type URL. If you get a 404 or 'Invalid record', the ID is genuinely wrong.
Step 2: Check the internal ID type
SuiteScript 2.x is strict about the 'id' parameter type. record.load({ type: 'salesorder', id: '123' }) works, but some edge cases require the integer 123. Log the exact ID value and type you're passing. Also verify you're not accidentally passing a string like '123.0' from a formula field.
Step 3: Confirm the record type is correct
Internal IDs are only unique within a record type. ID 123 as a Sales Order and ID 123 as an Invoice are different records. Check your code is using the correct record.Type constant. A common mistake is using search results from one record type to load a different type.
Step 4: Add existence checks before loading
Use search.lookupFields or a quick search to verify the record exists before calling record.load. This is especially important in async workflows where the record might have been deleted between steps.
Code Example
/**
* @NApiVersion 2.1
*
* Pattern: safe record load with existence check.
* Uses lookupFields (5 units) to verify before load (10 units).
* Saves 10 governance units on every failed load attempt.
*/
define(['N/search', 'N/record', 'N/log'], (search, record, log) => {
/**
* Safely loads a record, returning null if it doesn't exist.
* @param {string} type - record.Type value
* @param {number|string} id - internal ID
* @returns {record.Record|null}
*/
function safeLoad(type, id) {
if (!id) {
log.debug('safeLoad', `Skipping — no ID provided for ${type}`);
return null;
}
// Quick existence check (5 governance units)
try {
search.lookupFields({ type, id, columns: ['internalid'] });
} catch (e) {
log.debug('safeLoad', `${type} #${id} does not exist: ${e.message}`);
return null;
}
// Record confirmed to exist — load it (10 governance units)
return record.load({ type, id });
}
return { safeLoad };
});Common Mistakes
- Hardcoding internal IDs — they differ between sandbox and production environments. Use script parameters or custom records to store configurable IDs.
- Not handling the error in afterSubmit — if a related record was deleted between beforeSubmit and afterSubmit, the load will fail
- Confusing 'external ID' with 'internal ID' — search.lookupFields uses internal ID, but some integrations pass external IDs. Use record.Type and externalId parameter for external ID lookups.
- Caching internal IDs in script parameters that become stale after record merges or deletions
Alternative Approaches
- Use search.lookupFields() for read-only access — it's lighter (5 units vs 10 for record.load) and returns null-equivalent data if the record is missing
- For integrations, always use external IDs (externalid field) instead of internal IDs — they're stable across environments
- Implement a retry-with-search pattern: if load fails, search for the record by a stable identifier (e.g., name, external ID, tranid) to find the current internal ID