Common JavaScript errors, explained
The ten error messages developers paste into search bars most often: what each one means, how Chrome, Firefox and Safari word it differently, a minimal reproduction, and the fix.
InteractivePaste your exact error and jump to the right fix. Open Error Message Decoder →
JavaScript error messages are short, and they don't always point at the line that caused the problem. They also differ between engines: Chrome, Edge and Node.js run V8, Firefox runs SpiderMonkey, and Safari runs JavaScriptCore, and each words the same failure its own way. The MDN JavaScript error reference lists the variants side by side, and we use it as the main source below. The V8 messages on this page were also checked by running the snippets in Node.js 24.
Every message has three parts: the error type (TypeError, ReferenceError, SyntaxError, RangeError), the message, and a stack trace. Read the type first, because it narrows the cause before you read anything else.
| Error type | What it means | Typical cause |
|---|---|---|
TypeError | The value exists but is the wrong kind for the operation | Reading a property of undefined, calling a non-function, reassigning a const |
ReferenceError | The name can't be resolved, or isn't usable yet | Typos, wrong scope, the temporal dead zone |
SyntaxError | The code (or JSON) can't be parsed | Missing brackets, stray commas, HTML parsed as JSON |
RangeError | A value is outside the allowed range | Runaway recursion, invalid array length |
TypeError: Cannot read properties of undefined (reading 'x')#
This is the most common JavaScript error by a wide margin. You read a property, or called a method, on something that turned out to be undefined or null. MDN lists the engine variants:
V8 (Chrome/Edge/Node): TypeError: Cannot read properties of undefined (reading 'x')
Firefox: TypeError: "x" is undefined
Safari: TypeError: undefined is not an object (evaluating 'obj.x')
The property name in the message is the one you were trying to read. The thing that was undefined is whatever sits to its left. In user.profile.name failing with (reading 'name'), the culprit is user.profile.
const res = await fetch("/api/user");
const user = await res.json();
console.log(user.profile.name); // profile missing for some usersconst name = user?.profile?.name ?? "Anonymous";
// or check explicitly before you use it
if (user && user.profile) { render(user.profile.name); }Optional chaining returns undefined instead of throwing. Use it when the data really can be missing. If it should never be missing, find out why it is.
Common sources: an API response shaped differently than you assumed, array access past the end (items[items.length]), DOM queries that matched nothing (document.querySelector returns null), and reading state before an asynchronous load finishes.
TypeError: x is not a function#
All three engines use essentially the same wording here, according to MDN. You put () after something that isn't callable.
TypeError: o.foo is not a function
- Typos in method names. MDN's own example is
document.getElementByID. The method isgetElementById. - The method exists on a different type.
obj.map(...)on a plain object fails becausemaplives on arrays. UseObject.entries(obj).map(...). - A property shadows the method. Assigning
this.name = "Ralph"replaces a prototype method also calledname. - Wrong import style. Importing a default export with named-import braces, or the reverse, gives you
undefined. - Implicit multiplication.
2(3 + 5)is parsed as calling the number2.
ReferenceError: x is not defined#
V8 / Firefox: ReferenceError: x is not defined
Safari: ReferenceError: Can't find variable: x
The name was never declared anywhere the current code can see. MDN gives three usual causes: a typo or missing declaration, a variable declared inside a function and used outside it, or a library (such as jQuery's $) used before its <script> tag loaded. Check the spelling and capitalisation first, because identifiers are case-sensitive.
ReferenceError: Cannot access 'x' before initialization#
V8: ReferenceError: Cannot access 'x' before initialization
Firefox: ReferenceError: can't access lexical declaration 'x' before initialization
Safari: ReferenceError: Cannot access uninitialized variable.
This is the temporal dead zone. let, const and class declarations are hoisted, but they stay uninitialized until the declaration line runs, and touching them before then throws. var doesn't throw. It quietly gives you undefined, which is often worse. MDN points out that what counts is execution order, not source order, and that circular ES module imports are a classic trigger.
function total() {
console.log(tax); // ReferenceError
const tax = 0.08;
}function total() {
const tax = 0.08;
console.log(tax); // 0.08
}TypeError: Assignment to constant variable#
V8: TypeError: Assignment to constant variable.
Firefox: TypeError: invalid assignment to const 'x'
Safari: TypeError: Attempted to assign to readonly property.
const makes the binding read-only, not the value. Changing obj.foo on a const obj is fine. Writing obj = {} is not. MDN's fixes: switch to let if the value really must change, or use a new name. A frequent version of this bug is for (const i = 0; i < n; i++), because the i++ reassigns the constant.
SyntaxError: Unexpected token#
V8: SyntaxError: Unexpected token ';'
SyntaxError: Unexpected identifier 'x'
Firefox: SyntaxError: expected expression, got ';'
The parser hit a character it couldn't fit into valid grammar. MDN's tip is the useful part here: the reported position is often after the real mistake, so look at the lines above it. Usual causes are a missing closing bracket, a trailing comma inside an expression, or if (a) || (b) with the parentheses in the wrong place. If the "token" is < in a .js file, your server probably returned an HTML page where a script was expected.
SyntaxError: Unexpected end of JSON input (and other JSON.parse errors)#
JSON.parse and response.json() throw a SyntaxError when the text isn't strict JSON. These are the V8 messages we reproduced in Node.js:
JSON.parse("") → Unexpected end of JSON input
JSON.parse("<!DOCTYPE html>") → Unexpected token '<', "<!DOCTYPE html>" is not valid JSON
JSON.parse({}) → "[object Object]" is not valid JSON
JSON.parse('{"a":1,}') → Expected double-quoted property name in JSON at position 7
Firefox prefixes its versions with JSON.parse:, for example unexpected end of data or expected property name or '}' (MDN). The usual causes:
- An empty body, for example from a
204 No Contentor a failed request, parsed as JSON. - An HTML error page parsed as JSON. See 500 errors and 404 errors.
- Trailing commas, single quotes, unquoted keys or comments. These are valid in JavaScript object literals but not in JSON.
- Passing an object that's already parsed back into
JSON.parse.
const res = await fetch(url);
const text = await res.text();
if (!res.ok) throw new Error(`HTTP ${res.status}: ${text.slice(0, 200)}`);
const data = text ? JSON.parse(text) : null;
RangeError: Maximum call stack size exceeded#
V8 / Safari: RangeError: Maximum call stack size exceeded
Firefox: InternalError: too much recursion
Too many function calls were nested at once. MDN lists a recursive function with no base case, a base case that's never reached, and a sneakier one: a setter that assigns to its own property and so calls itself forever.
class Person {
set name(v) { this.name = v; } // calls the setter again
}class Person {
set name(v) { this._name = v; }
get name() { return this._name; }
}Very deep but finite recursion, such as walking a large tree, can also hit the limit. Rewrite it as a loop with an explicit stack.
Uncaught (in promise)#
When a promise rejects and nothing handles the rejection, browsers fire an unhandledrejection event and, if nothing cancels it, log an error to the console. Chrome writes the reason after Uncaught (in promise). In Node.js, the --unhandled-rejections default became throw in v15.0.0, so an unhandled rejection with no handler is raised as an uncaught exception and stops the process.
button.onclick = () => {
saveDraft(); // returns a promise that may reject
};button.onclick = async () => {
try { await saveDraft(); }
catch (err) { showToast("Couldn't save, try again"); }
};Access to fetch has been blocked by CORS policy#
Chrome: Access to fetch at 'https://api.example.com/' from origin 'https://app.example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present...
Firefox: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote
resource at https://api.example.com/. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
CORS errors confuse people because the request often did reach the server. The browser just refused to let your script read the response. MDN notes that for security reasons the details "are not available to JavaScript code": your catch only sees a generic network failure, and the real reason is in the console.
The fix is on the server. Send Access-Control-Allow-Origin with your origin, or with * for truly public, credential-free APIs. When cookies or multiple origins are involved, echo back an allowed Origin and add Vary: Origin (MDN). If you don't control the server, route the call through your own backend.
A debugging checklist#
- Read the error type first, then the message, then the first stack frame in your own code.
- Log the value just before the failing line. Most TypeErrors come down to "this wasn't what I thought it was".
- For network-related errors, open the Network tab and check the status code and response body before blaming your parsing code.
- Reproduce it in the smallest possible snippet. If the error disappears, the cause is in what you removed.
Frequently asked questions
Why does Chrome say "Cannot read properties of undefined" when Safari says "undefined is not an object"?
They are the same error. Each JavaScript engine words its messages differently: V8 (Chrome, Edge, Node.js) says Cannot read properties of undefined (reading 'x'), Safari's JavaScriptCore says undefined is not an object (evaluating 'obj.x'), and Firefox says "x" is undefined. All three are a TypeError raised because you tried to read a property of undefined.
Can I fix a CORS error in my front-end code?
Usually not. The browser blocks the response because the server did not send an Access-Control-Allow-Origin header that allows your origin. The fix belongs on the server (or a proxy you control). Setting mode: "no-cors" only makes the response opaque, so your script still cannot read it.
What does "Uncaught (in promise)" mean?
A promise was rejected and nothing handled the rejection: no .catch(), no second argument to .then(), and no try/catch around an await. Browsers report it in the console. In Node.js 15 and later the default is to treat it as an uncaught exception, which ends the process.
Why does JSON.parse fail with "Unexpected token <"?
The text you parsed starts with <, which almost always means the server sent back an HTML page (an error page, a login redirect, or a 404) instead of JSON. Log the raw response text and check the HTTP status and Content-Type header before parsing.
Is "Maximum call stack size exceeded" always caused by recursion?
Nearly always. It means too many function calls were nested at once, usually because a recursive function has no reachable base case. A common hidden version is a setter that assigns to its own property, which calls the setter again forever.
Sources
Every factual claim on this page links to one of these. Checked October 2026. See how we source.
- MDN: JavaScript error reference developer.mozilla.org
- MDN: TypeError: "x" is undefined / can't access property developer.mozilla.org
- MDN: TypeError: "x" is not a function developer.mozilla.org
- MDN: ReferenceError: "x" is not defined developer.mozilla.org
- MDN: SyntaxError: unexpected token developer.mozilla.org
- MDN: SyntaxError: JSON.parse: bad parsing developer.mozilla.org
- MDN: InternalError: too much recursion developer.mozilla.org
- MDN: TypeError: invalid assignment to const developer.mozilla.org
- MDN: ReferenceError: can't access lexical declaration before initialization developer.mozilla.org
- MDN: Window: unhandledrejection event developer.mozilla.org
- MDN: CORS errors developer.mozilla.org
- MDN: Reason: CORS header 'Access-Control-Allow-Origin' missing developer.mozilla.org
- MDN: Optional chaining (?.) developer.mozilla.org
- Node.js CLI docs: --unhandled-rejections nodejs.org