JSON Lint / Unexpected token errors / "u" at position 0

Unexpected token u in JSON at position 0

This specific error means one thing: you passed undefined to JSON.parse. The parser stringifies it to the four characters u-n-d-e-f-i-n-e-d, sees a u where it expected a valid JSON value, and gives up at position 0.

Open the linter →

The minimal reproduction

JSON.parse(undefined);
// SyntaxError: Unexpected token u in JSON at position 0

That's it. Any code path that funnels undefined into JSON.parse produces this exact error. Your job is finding which path.

The five places undefined sneaks in

1. localStorage / sessionStorage for a missing key

localStorage.getItem("settings") returns null for a missing key — but if you wrapped it:

function loadSettings() {
  const v = localStorage.getItem("settings");
  if (!v) return; // implicit return undefined!
  return JSON.parse(v);
}

const s = loadSettings();
const parsed = JSON.parse(s); // ← undefined here

Fix: return null explicitly, or check at the call site.

2. fetch() called on the Response object instead of the body

const res = await fetch("/api/user");
const data = JSON.parse(res);          // ← wrong — res is a Response object
const data = JSON.parse(await res);    // ← still wrong
const data = await res.json();         // ← correct
const data = JSON.parse(await res.text()); // ← also correct

JSON.parse(response) stringifies the Response object to something like "[object Response]" — the first char is [, not u, so this usually triggers "Unexpected token o" instead. But if you wrap a function that sometimes returns the body and sometimes returns nothing, you can hit u too.

3. React state read before the fetch resolves

const {data} = useFetch("/api/user");
const parsed = JSON.parse(data); // ← data is undefined on first render

Fix: guard. if (!data) return null; before parsing, or only parse inside the effect that sets data.

4. process.env.SOMETHING for an unset env var

// .env doesn't have CONFIG set
const cfg = JSON.parse(process.env.CONFIG); // ← undefined → error

Fix: default at the read site. JSON.parse(process.env.CONFIG ?? "{}"). Or validate env at boot with a schema (Zod, valibot) that fails loudly if a required var is missing.

5. Function that returns nothing on the unhappy path

function getJson(key) {
  if (cache.has(key)) return cache.get(key);
  // forgot to return on the miss path → implicit undefined
}

const x = JSON.parse(getJson("user")); // ← intermittent error

Fix: TypeScript with noImplicitReturns: true catches these at build time. In plain JS, return null explicitly on every branch.

The defensive parse helper

If you're parsing JSON from untrusted upstream code, wrap it:

function safeParse(v, fallback = null) {
  if (typeof v !== "string" || !v) return fallback;
  try {
    return JSON.parse(v);
  } catch {
    return fallback;
  }
}

Two layers: the type/empty check kills the undefined case; the try/catch kills every other parse error. Returns your fallback on either failure.

Related errors

FAQ

Why specifically the letter 'u'?

JSON.parse stringifies its argument before parsing. When you pass undefined, JavaScript converts it to the string "undefined" — the parser sees a 'u' as the first character, doesn't recognize it as the start of any JSON value (which must start with {, [, ", a digit, t, f, or n), and throws at position 0.

Does this happen with null too?

No — null is valid JSON, so JSON.parse(null) succeeds (it stringifies to the four characters n-u-l-l, which is the JSON null literal). The error only triggers with undefined, or with any value whose toString starts with 'u' (rare in practice).

How do I detect this before parsing?

Three guards stack: (1) check the value isn't null or undefined, (2) check it's a string, (3) check it has length. `if (typeof v !== 'string' || !v) return null;` handles all three. Then JSON.parse only sees real strings.

Why does my test for localStorage break only in incognito mode?

Incognito clears localStorage between sessions, so keys you wrote in a prior test run aren't there. `localStorage.getItem('key')` returns null for missing keys — null stringifies to "null" (valid JSON), so this specific error is more often undefined-from-a-function than missing-from-storage. But the pattern is the same: guard before parsing.

Is there a difference between this and 'Unexpected token < in JSON at position 0'?

Yes. The 'u' variant means undefined; the '<' variant means the server returned HTML (often an error page). Different root causes, same surface symptom. Check the input string before assuming it's a JSON producer bug.

Paste your JSON to find the error position →