ReferenceError in JavaScript: a name that exists nowhere

A ReferenceError reports an identifier missing from the current scope: the three usual causes, the temporal dead zone, and the part strict mode plays.
3 min read
Believemy logo

A name written in code has to stand for something. When the engine looks for that name everywhere it is allowed to look and finds nothing, it stops dead.

The message is short and unambiguous, which makes this one of the easiest errors to fix, with a single exception.


Definition

A ReferenceError is thrown when an identifier in use is declared in no reachable scope. The value is not wrong: the name simply does not exist.

JAVASCRIPT
try {
  console.log(user);
} catch (err) {
  console.log(err.name);      // ReferenceError
  console.log(err.message);   // user is not defined
}

// No error at all, because typeof tolerates unknown names
console.log(typeof user);   // undefined

typeof is the one operation that tolerates an unknown name. It is a useful survival for testing whether a global object is present without breaking.


The three usual causes

  • A typo. The most common case, and the one an editor flags before the code even runs.
  • A forgotten import. The name exists in another file, but nothing brought it into this one.
  • A global object absent from the environment. document and window do not exist under Node.js, process does not exist in a browser.

That last point accounts for most of the ReferenceError messages seen in a modern project, where the same code may run on the server and then in the browser.


The temporal dead zone

This is the exception announced above, and it throws people because the name does exist. A variable declared with let or const is reserved from the moment its block is entered, but stays unreachable until its declaration line.

JAVASCRIPT
try {
  console.log(counter);
  let counter = 1;
} catch (err) {
  console.log(err.message);   // Cannot access 'counter' before initialization
}

// With var, no error but an unusable value
console.log(total);   // undefined
var total = 10;

The message differs sharply from is not defined: it tells you the declaration sits further down in the same block. With var, the same code raises nothing and hands back undefined, producing a silent defect instead of a clear error.

Good to know

Outside strict mode, assigning to an undeclared name creates a global variable rather than raising an error. Modules are always in strict mode, which restores the expected ReferenceError: one more reason to work in modules.


Frequently asked questions

Question

Why does document is not defined show up when the server starts?

Because the code runs on the server first, where the browser document does not exist. The read then has to move into an effect fired after display, or be guarded by a test for the presence of the global object.


Question

How does it differ from a TypeError?

A ReferenceError happens before any use: the name cannot be found. A TypeError comes after: the name exists, so does the value, but that value does not support the operation asked of it. The first is fixed in the declaration, the second in the data.


Question

How do you avoid these errors instead of meeting them at runtime?

A static analyzer reports them as you type: a dedicated ESLint rule refuses any undeclared name, and TypeScript flatly refuses to compile. Both turn a runtime failure into a warning in the editor, which changes the cost of the mistake entirely.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.