JavaScript “is not defined”: Fix Scope, Imports & Load Order

ReferenceError: x is not defined means JavaScript could not resolve the identifier x in the active lexical/module/global environment. Start from the exact identifier and first application stack frame. Do not treat it as an undefined object property, package-install problem, or generic bundler failure until you prove who was supposed to define that name.

JavaScriptBrowsers · Node.jsLast reviewed Oct 29, 2026
🎯 You’re likely in the right place if:
The console shows ReferenceError: ... is not defined.The name is a variable, function, imported symbol or library global.The error appears when code first tries to read that identifier.
Choose the path that matches what you see
Name was never declaredDeclare it or import it in the scope where the failing line runs.
Name exists elsewhereCheck block/function/module scope and the first stack-trace frame.
Name comes from a browser library globalConfirm the script succeeds, actually exposes that global, and executes before the consumer.
Works in classic script, fails in type="module"Check explicit imports/module scope; do not assume top-level declarations become window globals.
Error is really “Cannot read properties of undefined”Stop here: the identifier resolved, but a value/property chain is undefined. Follow the separate TypeError guide.
Message says “before initialization”That is a temporal-dead-zone case; move the access after the let/const initialization instead of treating it as a missing global.
Difficulty: Easy–ModerateRisk: Low first
🔎 Quick Check — start from the first stack-trace frame

First-party reproduction run on Oct 29, 2026 in Node.js v24.22.1: reading an undeclared name produced “ReferenceError: formatValue is not defined”; declaring it before use printed 42. This confirms the basic missing-identifier case in Node.js only. Browser script order, module loading and bundler output need checks in their own runtime.

node -e 'console.log(formatValue)' # ReferenceError: formatValue is not defined node -e 'const formatValue = value => String(value); console.log(formatValue(42))' # 42

Verify: You can now name the expected owner: local/enclosing declaration, explicit module import, or intentional browser global. If the failing expression is property access on an already-resolved value, this is the wrong error class.

Did this reveal the missing name or scope?
ADSENSE · reserved slot after the first useful step

Why this happens

This error is about identifier resolution. The name may never have been declared, may be outside the current block/function/module scope, may be missing an import, or may be an expected browser global that was never created. This differs from obj.x where obj resolves but its value/property is wrong—that usually produces a TypeError or undefined value rather than saying identifier x is not defined.

Diagnose before changing more

1
Is the spelling identical?
JavaScript identifiers are case-sensitive, so userData and userdata are different names.
2
Was the name declared inside another scope?
Values declared with let or const inside a block are not visible outside that block.
3
Is it provided by another script or module?
Confirm that the import exists or that the dependency script loads before code that uses its global.
4
Classic script or ES module?
Module code has its own scope and should use explicit imports/exports. Do not assume a top-level module binding is a property on window.
5
External browser script uses async/defer/module?
Read the actual execution semantics. Merely placing one script tag above another is not sufficient when async allows independent execution timing.
6
Only production/bundled output fails?
Inspect the emitted/imported symbol and failing bundle/chunk rather than creating a global workaround in source.

Fix #2 — declare or import the identifier in the correct scope

If the name belongs to your code, declare it before use or import/export it through the module boundary that needs it. Avoid creating accidental globals just to silence the error.

// module-a.js export function formatValue(v) { return String(v); } // module-b.js import { formatValue } from './module-a.js';
🟡 Before changing configuration: Keep the declaration as narrow as practical. Moving everything to global scope can hide the real architecture problem.

Verify: Reload or rerun the exact failing path. The original ReferenceError should disappear; if a different error appears, follow that new error instead of continuing to change scope.

Did Fix #2 work?

Fix #3 — browser global: prove load success, export and execution order

If the identifier is intentionally provided by a classic browser library, verify three separate facts: the request succeeded, that build/version actually creates the expected global, and the provider executes before the consumer. For module-based libraries, use the documented import instead of assuming a global exists.

<script src="library.js"></script>\n<script src="app.js"></script>
🟡 Script attributes matter: Plain classic scripts execute in document order, while async scripts execute when available and can break an assumed provider→consumer order. defer and module scripts have different scheduling semantics. Check the actual tags before “fixing” order by moving lines around.

Verify: Reload the page with DevTools Network open. The dependency request should succeed, and the first stack frame should no longer report the missing global.

Did Fix #3 work?

What not to do

Do not create a new global variable just to silence the error unless the application intentionally uses that global API.Do not reorder unrelated scripts without confirming which dependency provides the missing name.Do not confuse this with “Cannot access X before initialization”; that message points to lexical initialization order, not the ordinary missing-identifier branch.Do not create window.x just to make a module-scoped import/declaration visible globally.Do not assume moving an async script tag higher guarantees it executes first.Do not install/reinstall an npm package merely because its expected identifier is missing; first prove the import or global that should create the identifier.

Still seeing the error?

If source code appears to contain the name but the runtime still reports it undefined, inspect the runtime context that produced the stack trace: exact module/file, emitted bundle, route and script execution order. For bundlers, confirm that the expected import survives into the failing output and that you are debugging the same build being served. Do not classify every chunk/dynamic-import failure as this ReferenceError; follow the first concrete runtime/network/module error when it differs.

Before escalating, capture:the exact ReferenceError text and first stack framethe declaration/import you expected to provide the namewhether the failure occurs in browser, Node.js, or only after bundlingthe smallest reproducible file or routewhether the failing code is classic script, ES module, Node/CommonJS, or bundled outputfor browser globals, the provider script URL/status and its async/defer/type attributeswhether the identifier should be local, imported, or intentionally global

References and related guides

Still stuck? Ask the community

Share your operating system, software version, exact error text, and which fix you already tried. Another reader may have seen the same setup.

Keep it safe: never post passwords, API keys, access tokens, recovery codes, license keys, private URLs, or confidential logs.
Powered by GitHub DiscussionsSign in with GitHub to comment. Reading comments does not require sign-in.

Loading community discussion…