JSON Object Keys Must Be Strings – Why and How

The JSON specification has a simple rule for object keys: they must be strings, and those strings must be enclosed in double quotes. This rule catches developers who write JSON by hand and forget the quotes, or who try to serialize Python dicts with integer keys or JavaScript Maps with non-string keys.

Valid vs invalid key syntax

// Invalid JSON — unquoted key
{ name: "Alice" }

// Invalid JSON — numeric key (bare number, not a string)
{ 42: "the answer" }

// Valid JSON — all keys are double-quoted strings
{ "name": "Alice", "42": "the answer" }

The parser throws a SyntaxError the moment it encounters a key that is not a double-quoted string. Common error messages include: Expected property name or '}' or Unexpected token n in JSON at position 2.

Why this rule exists

In JavaScript, object keys can be unquoted identifiers ({ name: "Alice" }), which makes JavaScript object literals easier to write. But JSON is a data interchange format shared across languages. Python, Java, Go, and other languages have their own rules about what constitutes a valid key in a dictionary or map. By requiring all keys to be strings, JSON provides a universal key type that every language understands.

JavaScript's automatic key conversion

A quirk of JavaScript is that all object keys are coerced to strings internally. If you write { 42: "value" } in JavaScript, the key is actually stored as the string "42". When JSON.stringify() serializes this object, it outputs {"42":"value"} — valid JSON with a quoted string key:

const obj = { 42: "the answer" };
console.log(JSON.stringify(obj)); // '{"42":"the answer"}'

This is why writing numeric keys in JavaScript does not cause serialization problems — they are already strings by the time stringify runs. The problem appears when you write JSON by hand and use a bare number as a key.

JavaScript Maps with non-string keys

JavaScript's Map supports any value as a key, including numbers and objects. But JSON.stringify() does not know how to serialize a Map:

const map = new Map([[1, "one"], [2, "two"]]);
JSON.stringify(map);
// '{}' — silently produces an empty object, no error

To serialize a Map to JSON, convert it to an object first. If the keys are numeric, they will be coerced to strings in the output:

JSON.stringify(Object.fromEntries(map));
// '{"1":"one","2":"two"}'

Duplicate keys in JSON

The JSON spec does not forbid duplicate keys — it says behavior is undefined when two properties have the same key. Most parsers accept the document and use the last value seen for that key. This is generally a bug in the source data. Use the JSON Validator to detect duplicate keys before they cause silent overwrites in your application.

Python dict serialization

Python's json.dumps() handles integer keys similarly to JavaScript — it converts them to strings:

import json
data = {1: "one", 2: "two"}
print(json.dumps(data))
# '{"1": "one", "2": "two"}'

However, json.dumps() will throw a TypeError if a key cannot be converted to a string at all (for example, if you use a tuple as a key).

Related articles