Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

SyntaxError Unexpected Token: The Five Things It Actually Means in JavaScript and TypeScript

Sean

Platform Writer

Jun 18, 2026
6 min read

The first thing every developer does when they see SyntaxError: Unexpected token is count the brackets on the line the error points to. That fixes the error about 30% of the time. The other 70% of the time, the brackets are fine, and the parser is confused by something earlier in the file that makes the current line look like nonsense. Five failure modes, one error message.

SyntaxError Unexpected Token: The Five Things It Actually Means in JavaScript and TypeScript

Table of contents

The honest short version: Unexpected token means the parser reached a character that does not fit the grammar it expected. The character is usually correct; the context is usually wrong. Look at the line above the error, look at the file the error is in (especially for transpiled code), and look at the version of the parser you are running. The fix is rarely on the line the error points at.

SyntaxError Unexpected Token: the five things it actually means in JavaScript and TypeScript

Table of contents

The direct answer

The five-step diagnostic:

  1. Look at the line above the error. Most Unexpected token errors point one line too late. The mistake is usually on the previous line.
  2. Look at the file the error is in. If it is in dist/ or build/, the error is in the source file, not the built file. Trace the source map.
  3. Run the parser directly. node --check file.js parses without executing; the error message is often clearer.
  4. Check the parser version. Node 14 parses differently than Node 20. TypeScript 4 parses differently than TypeScript 5.
  5. Bisect the file. Comment out half the file. If the error goes away, the mistake is in the half you commented out. Repeat.

In practice, step 1 catches the most cases. Step 5 catches the rest.

Failure 1: a missing or extra bracket from earlier in the file

The most common cause of Unexpected token. The parser hits a line that looks fine in isolation, but it is missing a closing brace, paren, or bracket from earlier, so the current line is in the wrong scope.

Example:

function process(data) {
  if (data.valid) {
    return data.value;
// missing closing brace for if
// missing closing brace for function

console.log(result);

The error will be Unexpected token 'console' on the last line. The mistake is the missing } two lines up. The parser is looking for the end of the function and finds console.log instead.

The diagnostic: count the opening and closing braces in the file. They should match. Use an editor that highlights matching braces (VS Code does this by default; position the cursor on { and the matching } is highlighted).

A faster diagnostic: node --check file.js prints the line number of the error and the column. The column often points at the character that does not fit, not the line where the actual mistake is.

Failure 2: a reserved word used as an identifier

The parser refuses to let you use a reserved word as a variable name. The error is Unexpected token '<word>' where <word> is something like class, enum, import, await, let, static, or yield.

Example:

const class = "biology"; // SyntaxError: Unexpected token 'class'
const enum = "red"; // SyntaxError: Unexpected token 'enum'

The fix: rename the variable. className, enumValue, etc.

A subtler version: using a reserved word in a property name where the parser expects an identifier. Example:

const obj = {
  class: "biology", // SyntaxError: Unexpected token 'class'
  enum: "red"       // SyntaxError: Unexpected token 'enum'
};

The fix: use a string key. obj = { "class": "biology", "enum": "red" } works.

A list of reserved words to avoid as identifiers: break, case, catch, class, const, continue, debugger, default, delete, do, else, enum, export, extends, false, finally, for, function, if, import, in, instanceof, new, null, return, super, switch, this, throw, true, try, typeof, var, void, while, with, yield, plus the strict-mode reserved words implements, interface, let, package, private, protected, public, static.

Failure 3: a TypeScript feature in a JavaScript file

The parser refuses to parse TypeScript syntax in a .js file. The error is Unexpected token ':' (for type annotations), Unexpected token '<' (for generics), or Unexpected token 'as' (for type assertions).

Example:

// file.js
function add(a: number, b: number): number {
  return a + b;
}

Run with Node directly and the error is Unexpected token ':' because Node parses the file as JavaScript, not TypeScript.

The fix depends on the situation:

  • If the file is meant to be TypeScript, rename to .ts and run with ts-node, tsx, or compile with tsc.
  • If the file is meant to be JavaScript, remove the type annotations.
  • If the file is meant to be both, use JSDoc comments for types and let TypeScript check them via tsc --checkJs.

For build pipelines, the equivalent failure is the parser running on the wrong file. Webpack with ts-loader parses TypeScript. Webpack with babel-loader does not. Make sure the loader matches the file extension.

Failure 4: a Node/browser feature mismatch

The parser refuses to parse a feature that does not exist in the runtime’s version. The error is Unexpected token '??' (nullish coalescing, ES2020), Unexpected token '?.' (optional chaining, ES2020), Unexpected token '|>' (pipeline, ES2025), etc.

Example:

const value = data?.field ?? "default"; // works in Node 14+, fails in Node 12

The diagnostic: check the Node version. node --version. If the file is meant to run in a browser, check the browser’s target.

The fix:

  • Upgrade the runtime. Most modern features work in Node 18+ and evergreen browsers.
  • Use a transpiler. Babel, TypeScript, or esbuild can downlevel the syntax.
  • Refactor the code. Replace data?.field ?? "default" with data && data.field || "default" for older runtimes.

For libraries, the right answer is usually to transpile with esbuild or swc and ship ES5. For applications, the right answer is usually to upgrade the runtime.

Failure 5: a transpilation pipeline mismatch

The parser refuses to parse the output of the transpiler. The error is in a file in dist/ or build/, but the mistake is in the source.

Example:

file:///app/dist/index.js:42
  const x: number = 5;
                ^
SyntaxError: Unexpected token ':'

The TypeScript compiler emitted .js files with TypeScript syntax still in them. Either the tsconfig.json is wrong, or the build was interrupted, or someone ran the wrong command.

The fix: regenerate the build. rm -rf dist && npm run build. If the error persists, the tsconfig.json has "target": "esnext" without "declaration": false, or some other misconfiguration.

A subtler version: the transpiler strips types but keeps syntax that the runtime does not understand. Example: esbuild with --target=node14 strips the type annotations but keeps ?? because Node 14 supports it. The output runs on Node 14. The output breaks on Node 12. The mismatch is between the build target and the runtime target. Check both.

The diagnostic that catches all five

The four commands, in order:

# 1. Parse without executing
node --check src/file.js

# 2. Try a different runtime
npx -p node@20 node --check src/file.js

# 3. Look at the source, not the build
grep -n "problematic_line" src/file.ts

# 4. Bisect the file
sed -n '1,50p' src/file.js > /tmp/half.js && node --check /tmp/half.js

Step 1 catches 70% of cases. Step 2 catches version mismatches. Step 3 catches build-vs-source confusion. Step 4 catches everything else by isolating the problem.

For projects that deploy on a managed platform like RunxBuild’s backend services, the build pipeline runs the same parsers as local development, and the build log shows the syntax error with the file and line number. The deploy refuses to start if the build fails. For the cost of running that Node service at production scale, the RunxBuild hosting calculator gives you the per-month number.

FAQ

Why is the syntax error pointing at the wrong line?

Because the parser is confused by something earlier in the file. The line the error points at is the line where the parser realized the previous lines did not form valid syntax. The mistake is usually on a previous line.

Why does my code work locally but fail in CI?

Either the Node version differs, the file extension is wrong (.js instead of .ts), or the build pipeline is different. Check all three.

How do I find syntax errors faster?

Use an editor with a language server (VS Code, WebStorm, Vim with coc.nvim). The language server highlights syntax errors as you type, before you run the parser.

Can I have a syntax error in a third-party package?

Yes, but it is rare. If node --check on a file in node_modules/ fails, your version of Node is probably too old to parse the syntax in the package. Upgrade Node or downgrade the package.

What is the difference between Unexpected token and Unexpected end of input?

Unexpected token is a character that does not fit. Unexpected end of input is the file ending before the parser expected it to (usually a missing closing brace, paren, or backtick).

Why does my template literal fail with Unexpected token?

You probably have an unescaped backtick inside the template. `${name}`'s value is fine; `${name}`s ` value is a syntax error because the second backtick closes the template early.

Can a JSON file produce a SyntaxError?

Yes, when parsed as JSON. JSON.parse('undefined') throws a SyntaxError. The fix is to validate the input before parsing.

Why does my arrow function fail with Unexpected token =>?

You probably wrote (a, b) => { a, b } instead of (a, b) => { return { a, b } } or (a, b) => ({ a, b }). The arrow body with { expects a function body, not an object literal. Wrap the object in parens.

FAQ

Why is the syntax error pointing at the wrong line?

Because the parser is confused by something earlier in the file. The mistake is usually on a previous line.

Why does my code work locally but fail in CI?

Either the Node version differs, the file extension is wrong (.js instead of .ts), or the build pipeline is different.

How do I find syntax errors faster?

Use an editor with a language server (VS Code, WebStorm, Vim with coc.nvim). The language server highlights syntax errors as you type.

Can I have a syntax error in a third-party package?

Rare. If node --check on a node_modules/ file fails, your Node is probably too old to parse the syntax. Upgrade Node or downgrade the package.

What is the difference between Unexpected token and Unexpected end of input?

Unexpected token is a character that does not fit. Unexpected end of input is the file ending before the parser expected it to.

Why does my template literal fail with Unexpected token?

You probably have an unescaped backtick inside the template. The second backtick closes the template early.

Can a JSON file produce a SyntaxError?

Yes, when parsed as JSON. JSON.parse('undefined') throws a SyntaxError. Validate the input before parsing.

Why does my arrow function fail with Unexpected token =>?

You probably wrote (a, b) => { a, b } instead of (a, b) => ({ a, b }). The arrow body with { expects a function body, not an object literal.

#JavaScript#TypeScript#Syntax Error#Node.js#Debugging