What Is JSON? The RFC 8259 Specification
JSON (JavaScript Object Notation) is a lightweight, text-based data interchange format defined in RFC 8259 (December 2017), which superseded RFC 7159 and the original RFC 4627. Despite its name, JSON is entirely language-independent — it is supported natively or via a standard library in virtually every programming language on the planet.
RFC 8259 defines exactly six value types:
- object — an unordered set of key/value pairs enclosed in
{} - array — an ordered list of values enclosed in
[] - string — a Unicode character sequence enclosed in double quotes
- number — an integer or floating-point value (finite only — no
NaN, noInfinity) - boolean — the exact literals
trueorfalse - null — the exact literal
null
RFC 8259 mandates UTF-8 encoding without a BOM for all JSON text transmitted over a network. UTF-16 and UTF-32 are technically permitted by the spec but rejected by the vast majority of parsers. In practice: always use UTF-8.
The specification is deliberately minimal — no comments, no trailing commas, no date literals, no binary types. This simplicity means a JSON document can be parsed by a deterministic finite automaton, which is why parsing is reliably fast even for megabyte-scale payloads.
JSON Syntax Rules Every Developer Must Know
The rules below are not conventions — they are hard requirements of the specification. Violating any of them produces invalid JSON that will cause a parse error in every standards-compliant parser.
- Keys must be double-quoted strings.
{"name": "Alice"}is valid.{name: "Alice"}and{'name': 'Alice'}are not. - No trailing commas. The last element in an array or the last key/value pair in an object must not be followed by a comma. This is the single most common JSON error.
- No comments. Neither
// line commentsnor/* block comments */are part of the JSON grammar. Use a separate documentation file or a superset like JSON5 if you need comments in config files. - Numbers have no leading zeros.
007is not valid JSON. Use7. The only exception is0itself, and numbers like0.5. - Strings must escape certain characters. The backslash, double quote, and control characters U+0000 through U+001F must be escaped. The valid escape sequences are:
\",\\,\/,\b,\f,\n,\r,\t, and\uXXXX. undefined,NaN, andInfinityare JavaScript values, not JSON values.JSON.stringify(NaN)in JavaScript returns"null", which surprises many developers.- Object keys are technically unordered. The spec says implementations must not rely on key ordering. In practice, most modern parsers and engines preserve insertion order, but you cannot depend on it in a standard-compliant way.
The 8 Most Common JSON Errors — With Exact Fixes
The following errors account for the overwhelming majority of JSON parse failures in the wild. Each is shown with the invalid JSON, the error a typical parser reports, and the corrected version.
Error 1: Trailing comma
The most common error by far. JavaScript allows trailing commas in object and array literals; JSON does not.
// ❌ Invalid
{"name": "Alice", "age": 30,}
// ✅ Valid
{"name": "Alice", "age": 30}
Error 2: Single-quoted strings
JavaScript accepts single quotes for strings; JSON requires double quotes for both keys and values.
// ❌ Invalid
{'name': 'Alice'}
// ✅ Valid
{"name": "Alice"}
Error 3: Unquoted keys
// ❌ Invalid — valid JS object literal, invalid JSON
{name: "Alice", age: 30}
// ✅ Valid
{"name": "Alice", "age": 30}
Error 4: JavaScript-only values
// ❌ Invalid — undefined, NaN, and Infinity are not JSON
{"score": NaN, "rank": undefined, "ratio": Infinity}
// ✅ Valid — use null or omit the key
{"score": null, "ratio": null}
Error 5: Missing comma between elements
// ❌ Invalid
{"name": "Alice" "age": 30}
["one" "two" "three"]
// ✅ Valid
{"name": "Alice", "age": 30}
["one", "two", "three"]
Error 6: Comments in JSON
// ❌ Invalid — JSON has no comment syntax
{
// User record
"name": "Alice", /* admin user */
"role": "admin"
}
// ✅ Remove comments, or use JSON5 / JSONC for config files
{"name": "Alice", "role": "admin"}
Error 7: Leading zeros in numbers
// ❌ Invalid — octal literal interpretation prevented by spec
{"zip": 07302, "code": 00124}
// ✅ Quote numeric codes that have meaningful leading zeros
{"zip": "07302", "code": "00124"}
Error 8: Unescaped control characters in strings
// ❌ Invalid — raw newline inside a JSON string
{"address": "123 Main St
Suite 400"}
// ✅ Use escape sequence
{"address": "123 Main St\nSuite 400"}How to Format JSON in 6 Programming Languages
Every major language has a built-in or standard-library way to pretty-print JSON. The examples below format a compact JSON string with 2-space indentation — the most common convention for readability.
const raw = '{"name":"Alice","scores":[98,87,92]}';
const obj = JSON.parse(raw);
const pretty = JSON.stringify(obj, null, 2);
console.log(pretty);
/* Output:
{
"name": "Alice",
"scores": [98, 87, 92]
}
*/import json
raw = '{"name":"Alice","scores":[98,87,92]}'
obj = json.loads(raw)
pretty = json.dumps(obj, indent=2)
print(pretty)
# Output:
# {
# "name": "Alice",
# "scores": [98, 87, 92]
# }package main
import (
"encoding/json"
"fmt"
)
func main() {
raw := []byte(`{"name":"Alice","scores":[98,87,92]}`)
var obj map[string]interface{}
json.Unmarshal(raw, &obj)
pretty, _ := json.MarshalIndent(obj, "", " ")
fmt.Println(string(pretty))
}use serde_json::Value;
fn main() {
let raw = r#"{"name":"Alice","scores":[98,87,92]}"#;
let obj: Value = serde_json::from_str(raw).unwrap();
let pretty = serde_json::to_string_pretty(&obj).unwrap();
println!("{}", pretty);
}# Pretty-print with jq (install: brew install jq / apt install jq)
echo '{"name":"Alice","scores":[98,87,92]}' | jq .
# From a file
cat data.json | jq .
# Sort keys + pretty-print
cat data.json | jq -S .
# Validate only (exit code 1 on error)
jq . data.json > /dev/null && echo "valid" || echo "invalid"import com.fasterxml.jackson.databind.ObjectMapper;
public class FormatJson {
public static void main(String[] args) throws Exception {
String raw = "{\"name\":\"Alice\",\"scores\":[98,87,92]}";
ObjectMapper mapper = new ObjectMapper();
Object obj = mapper.readValue(raw, Object.class);
String pretty = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(obj);
System.out.println(pretty);
}
}JSON Edge Cases That Catch Developers Off Guard
Large integer precision loss
JSON numbers are specified as arbitrary-precision, but JavaScript's JSON.parse() parses all numbers as IEEE 754 doubles. Any integer larger than Number.MAX_SAFE_INTEGER (253 − 1 = 9,007,199,254,740,991) will lose precision silently:
JSON.parse('{"id": 9007199254740993}')
// → { id: 9007199254740992 } ← wrong! lost 1
// Fix: receive large integers as strings
JSON.parse('{"id": "9007199254740993"}')
// → { id: "9007199254740993" } ← correct
This is a real-world problem with Twitter/X snowflake IDs (which exceed safe integer range). The Twitter API ships IDs as both a number field and a string field (id and id_str) specifically because of this limitation.
Duplicate keys — technically allowed, practically dangerous
RFC 8259 explicitly says objects with duplicate keys produce undefined behaviour. Most parsers silently take the last value, but some take the first, and some throw. Never produce JSON with duplicate keys.
Unicode and surrogate pairs
JSON is Unicode, but if your source data contains surrogate pairs (characters above U+FFFF encoded as two UTF-16 code units), some parsers will reject them unless they are correctly paired. \uD800 through \uDFFF are not valid standalone Unicode scalar values in JSON. Use a formatter or validator to surface these before they reach production.
The empty document
RFC 8259 says a valid JSON text is any single JSON value — not just an object or array. "hello", 42, true, and null are all complete, valid JSON documents. Many developers assume JSON must start with { or [; this is a common misconception.
Format vs Minify: When to Use Each
Format (pretty-print) during development, debugging, code review, and whenever a human needs to read the JSON. Indented JSON is also essential when storing JSON in version control — diffs are readable and reviewable.
Minify in production for payloads transmitted over a network. A 4-space indented JSON object can be 30–60% larger than its minified equivalent. For high-traffic APIs serving millions of requests per day, that overhead adds up to real bandwidth costs and measurable latency on slow connections.
The practical workflow: keep a formatted copy for development and source control; run minification as a build step or in your API serialiser at runtime. Never commit minified JSON that humans need to review — always commit the formatted version.