Skip to content
πŸ“Developer Tools

Why Your JSON Has `undefined`: How to Debug Invalid JSON in Any Language

JSON returning undefined or invalid JSON errors? Learn the most common causes - streaming output, character encoding, schema mismatches - and how to fix them fast.

Toolblip TeamΒ·2026-05-03T00:00:00.000ZΒ·3 min

If you've ever seen your API return { "user": undefined } or get hit with an Unexpected token u error, you're not alone. JSON undefined errors are one of the most commonθ°ƒθ―• problems developers face - and they're rarely caused by actual JSON syntax issues.

This guide walks through the real reasons JSON goes wrong, with code examples you can drop into any project, plus browser tools to debug faster.

Why Does JSON Return undefined?

The short answer: undefined is not valid JSON. It's a JavaScript concept that doesn't exist in the JSON specification. When you see undefined in your output, something in your code is serializing a JavaScript undefined value instead of converting it properly.

Here are the most common culprits:

1. JavaScript's JSON.stringify() on undefined Properties

By default, JSON.stringify() skips undefined values entirely - but sometimes that behavior bites you.

// These get silently dropped
JSON.stringify({ name: "Harun", role: undefined })
// β†’ '{"name":"Harun"}'

// But arrays preserve the slot (becomes null)
JSON.stringify({ tags: [1, undefined, 3] })
// β†’ '{"tags":[1,null,3]}'

// And dates become strings
JSON.stringify({ created: new Date() })
// β†’ '{"created":"2026-05-03T12:00:00.000Z"}'

If your output contains null where you expected a value, check your serialization chain - something is converting undefined to null.

2. Streaming Output Without a Collector

This is the big one that trips up a lot of Node.js developers. If you're streaming JSON responses and not buffering correctly, you get partial output:

// ❌ Broken: streaming without proper framing
async function* generateUsers() {
  yield '{"users":[';
  yield '{"name":"Alice"},';  // What happens if this never comes?
  yield '{"name":"Bob"}';
  yield ']}';
}
// If the stream closes early β†’ invalid JSON
// βœ… Fixed: collect then flush, or use proper NDJSON
async function* generateUsers() {
  const users = await db.users.findMany();
  // Buffer everything, then send once
  return { users };
}

If you're building an API that streams JSON, use NDJSON (newline-delimited JSON) or collect into a buffer before flushing.

3. Wrong Content-Type Headers

A subtle cause: your API is returning valid JSON but the client is parsing it as something else.

# If Content-Type is text/plain, browsers won't parse it as JSON
curl -i https://api.example.com/users
# HTTP/1.1 200 OK
# Content-Type: text/plain; charset=utf-8
#
# [{"name":"Alice"},{"name":"Bob"}]  ← treated as plain text!
# Correct: application/json
curl -i https://api.example.com/users
# HTTP/1.1 200 OK
# Content-Type: application/json; charset=utf-8
#
# [{"name":"Alice"},{"name":"Bob"}]  ← parsed correctly

4. Encoding Issues: BOM, UTF-8 Variants, Binary Mistaken for Text

A Byte Order Mark (BOM) at the start of a JSON file will cause parse errors in many JSON parsers:

// File saved as UTF-8 with BOM β†’ first character is \uFEFF
// Some parsers reject it, others accept it
const badJson = "\uFEFF{\"name\":\"Harun\"}";
JSON.parse(badJson); // ❌ "Unexpected token" in strict parsers

Node.js solution:

const fs = require('fs');

// Strip BOM automatically
const content = fs.readFileSync('data.json', 'utf8').replace(/^\uFEFF/, '');
const data = JSON.parse(content); // βœ… works

5. Trailing Commas (JSON Doesn't Allow Them)

// ❌ Invalid JSON  -  trailing commas not allowed
const bad = {
  name: "Harun",
  role: "admin",  // trailing comma!
};

// βœ… Valid JSON
const good = {
  name: "Harun",
  role: "admin"
};

If you're converting from JavaScript objects to JSON, watch out for code that allows trailing commas (like TypeScript's es5 target with strict: false).

6. Numeric Edge Cases: NaN, Infinity, BigInt

// ❌ These aren't valid JSON values
JSON.stringify({ rate: NaN });          // β†’ '{"rate":null}'  (silently converts!)
JSON.stringify({ rate: Infinity });    // β†’ '{"rate":null}'  (silently converts!)
JSON.stringify({ id: BigInt(9007199254740991) }); // β†’ throws!

// βœ… Fix: serialize BigInt manually
const safeStringify = (obj) => JSON.stringify(obj, (key, value) =>
  typeof value === 'bigint' ? value.toString() : value
);

How to Debug JSON Errors Fast

When JSON goes wrong, the first step is always the same: pretty-print it and look at the raw output.

Paste your JSON into Toolblip's JSON Formatter - it highlights syntax errors instantly and tells you exactly which line and character is broken.

For schema validation (is your JSON valid and does it match your expected structure?), use the JSON Schema Validator. It shows you precisely which fields are missing, have the wrong type, or violate constraints.

Common Error Patterns and What They Mean

Error Message Likely Cause Fix
Unexpected token 'u' Parsing undefined as JSON Check your serialization
Unexpected token '<' HTML response (wrong URL or CORS) Verify the endpoint
Unexpected token '\uFEFF' BOM at file start Strip the BOM
Unexpected end of JSON input Truncated stream Buffer before parsing
Comma is not valid after last element Trailing comma Remove the comma

Python, Go, and Rust Gotchas

JSON bugs aren't just a JavaScript problem.

Python: None Becomes null

import json

# Python None serializes fine, but sometimes deserializes wrong
data = json.dumps({"name": None, "role": None})
# β†’ '{"name": null, "role": null}'

# But if you're checking with isinstance(x, type(None)) you might miss it
parsed = json.loads(data)
print(parsed["name"] is None)  # True

Go: Empty Structs and Zero Values

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    // Zero values are serialized  -  no skipping by default
    user := User{Name: "Harun"}
    out, _ := json.Marshal(user)
    fmt.Println(string(out))
    // β†’ {"name":"Harun","age":0}  ← age is 0, not omitted
}

Use omitempty to skip zero values:

type User struct {
    Name string `json:"name,omitempty"`
    Age  int    `json:"age,omitempty"`
}

Rust: serde_json Is Strict

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Config {
    host: String,
    port: u16,
}

// This will error: missing field `port`
let json_str = r#"{"host":"localhost"}"#;
let config: Config = serde_json::from_str(json_str).unwrap();

Add #[serde(default)] to make fields optional:

#[derive(Serialize, Deserialize)]
struct Config {
    host: String,
    #[serde(default)]
    port: u16,  // defaults to 0 if missing
}

Quick Debugging Checklist

Next time you hit a JSON error, run through this:

  1. Pretty-print the raw output - use JSON Formatter to see the actual content
  2. Check Content-Type header - must be application/json
  3. Look for BOM - search for \uFEFF at the start
  4. Validate against a schema - use JSON Schema Validator to catch type mismatches
  5. Check for undefined, NaN, Infinity - these serialize differently across languages
  6. Check for trailing commas - especially if converting from JS objects

The Browser Tool Advantage

One of the biggest advantages of browser-based JSON tools? Nothing leaves your machine. When you're debugging sensitive API responses - auth tokens, database payloads, user data - you don't want that flowing through a third-party formatter.

Toolblip's JSON Formatter and JSON Schema Validator run entirely in your browser. Paste your JSON, get instant validation and formatting, and the data never touches a server.

Related Tools


Debugging JSON doesn't have to be a mystery. The error message almost always points you in the right direction - it just takes a bit of practice to read what it's telling you. Bookmark this guide, and next time you hit an Unexpected token error, you'll know exactly where to look.

Ready to try it yourself?

Browse Free Tools β†’