JSON Unquoted Keys SyntaxError — Why It Happens and How to Fix It

Quick answer

💡JSON requires every object key to be a double-quoted string. JavaScript object literal syntax allows unquoted keys, but JSON.parse rejects them with SyntaxError. The fastest fixes are: run your object through JSON.stringify to produce correct JSON, use a proper serializer in your language of choice, or if the source is hand-written config, add double quotes around every key. For config files that need unquoted keys, use JSON5 instead.

Error symptoms

  • SyntaxError: Unexpected token n in JSON at position 1 for input like { name: 'Alice' }
  • SyntaxError: Expected property name or '}' in JSON at position 1
  • JSON.parse throws immediately when the first key of the object is unquoted
  • A configuration file that works fine as JavaScript fails when read as JSON
  • A Python dict literal pasted into an API tester fails to parse
  • An online JSON editor reports 'invalid JSON' for input copied from JavaScript source code

Common causes

  • A JavaScript object literal copied directly into a JSON file or API request body without adding quotes to the keys
  • A Python dictionary literal pasted as JSON — Python uses the same dict syntax as JavaScript but quotes are optional for string keys in Python too
  • A developer writing a JSON config file by hand without realizing JSON has stricter key requirements than JavaScript
  • A template or code generator that emits JavaScript object notation rather than JSON
  • A REST client configured to send the request body as-is from a text field where the developer typed JavaScript syntax
  • A JSON5 file read by a tool that expects standard JSON — JSON5 allows unquoted keys but standard parsers do not

When it happens

  • When copying example code from documentation that shows JavaScript object literals rather than JSON
  • When a back-end developer writes a test fixture in JavaScript object notation and another service tries to read it as JSON
  • When a configuration management tool uses JSON5 syntax in its documentation but the deployed configuration reader expects standard JSON
  • When a developer pastes Postman collection examples or cURL responses that contain JavaScript-style objects into a JSON field
  • When a build tool or scaffolding script generates config files using JavaScript template literals rather than JSON.stringify

Examples and fixes

A developer copies a JavaScript object that represents a user profile into a JSON API request body. The JavaScript syntax uses unquoted keys, which JSON.parse rejects.

Converting a JavaScript object literal to valid JSON

❌ Wrong

// This is valid JavaScript but NOT valid JSON
{
  name: 'Alice Chen',
  age: 31,
  role: 'engineer',
  active: true,
  department: 'platform',
  startDate: '2021-03-15'
}

✅ Fixed

{
  "name": "Alice Chen",
  "age": 31,
  "role": "engineer",
  "active": true,
  "department": "platform",
  "startDate": "2021-03-15"
}

Every key in the broken version is an unquoted identifier — valid JavaScript object literal syntax, but invalid JSON. The fixed version wraps every key in double quotes and replaces single-quoted string values with double-quoted ones. Note that non-string values like the integer 31 and the boolean true do not get quotes — only keys and string values use double quotes in JSON. The fastest way to perform this transformation programmatically is to pass the object to JSON.stringify, which always produces correctly quoted keys and double-quoted string values.

A scaffolding script generates a project configuration file using JavaScript template literals. The output looks like JSON but uses unquoted keys, causing failures when config readers call JSON.parse.

Fixing an auto-generated config file with unquoted keys

❌ Wrong

// Generated by scaffolder — uses JS object notation, not JSON
const projectConfig = {
  projectName: 'data-pipeline',
  version: '2.4.0',
  environment: 'production',
  database: {
    host: 'db.internal.example.com',
    port: 5432,
    maxConnections: 20
  },
  features: { metrics: true, tracing: false }
};

✅ Fixed

{
  "projectName": "data-pipeline",
  "version": "2.4.0",
  "environment": "production",
  "database": {
    "host": "db.internal.example.com",
    "port": 5432,
    "maxConnections": 20
  },
  "features": { "metrics": true, "tracing": false }
}

The scaffolding script emits a JavaScript module with a const declaration and JavaScript object notation. The config reader expects a plain JSON file and calls JSON.parse on its contents, which fails on the const keyword and the unquoted keys. The fix is to update the scaffolding script to use JSON.stringify(config, null, 2) when writing the config file rather than generating JavaScript source code. The resulting file has no const keyword, all keys are double-quoted, and JSON.parse reads it without errors. As a migration step for existing generated files, the JSON formatter can reformat a manually corrected version.

JSON grammar requires every key to be quoted

The JSON specification in RFC 8259 defines the grammar for a JSON object precisely: an object is a pair of curly braces surrounding a comma-separated list of members, where each member is a string followed by a colon followed by a value. The definition of member begins with string — not identifier, not name, not token — and the definition of string requires it to begin and end with a double-quote character. There is no provision in the grammar for unquoted keys, and there never has been.

This stands in contrast to JavaScript's object literal syntax, which allows both unquoted identifiers and quoted strings as property names. In JavaScript, { name: 'Alice' } and { "name": "Alice" } are equivalent and both create an object with a single property. The ECMAScript specification explicitly permits identifier names as property names in object literals, which is why unquoted keys feel natural to JavaScript developers.

JSON was designed to be a language-independent data interchange format, not a subset of JavaScript. Although it was originally derived from JavaScript object literal notation and the name JSON stands for JavaScript Object Notation, the designers made a deliberate simplification by requiring keys to be strings. This means any language with a string type can parse JSON keys without understanding JavaScript's identifier lexer. Requiring double quotes also eliminates ambiguity about which identifiers are valid keys — in JavaScript, reserved words like class, for, and delete are allowed as unquoted keys in modern syntax but forbidden in older ECMAScript versions. By requiring quotes, JSON sidesteps all of this complexity.

The error message varies by JavaScript engine. V8 (Node.js and Chrome) typically says 'Unexpected token n in JSON at position 1' when the input is { name: 'Alice' } — the 'n' at position 1 is the first character of the unquoted key 'name', which is not a valid JSON token at that position. Firefox says 'JSON.parse: expected property name or '}' at line 1 column 2'. Both messages are telling you the same thing: the parser expected a string delimiter (a double-quote) and instead found the start of an unquoted identifier.

Spotting unquoted keys in failing payloads

When JSON.parse throws about an unexpected token at position 1 or 2, the most common cause is an unquoted key at the very beginning of the object. Position 1 in { name: 'Alice' } is the 'n' character, which comes immediately after the opening brace and the space. A correctly formatted JSON object would have a double-quote character at that position: { "name": "Alice" }.

For larger payloads, the error position may point to a nested object rather than the root. The JSON parser reads correctly until it encounters the first unquoted key and throws at that character's position. Count from position 0 to find the relevant section of the JSON text, or paste the payload into a validator that highlights the error line. Most validators highlight the specific token that caused the parse failure, making it visually obvious whether the issue is a missing quote, a trailing comma, or a different problem entirely.

A useful diagnostic technique is to run the text through a JSON5 parser, which accepts unquoted keys. If JSON5 parses it successfully and produces a sensible object, the input is valid JSON5 with unquoted keys. If even JSON5 fails, the input has deeper structural problems. This comparison tells you whether you need to add quotes or whether more significant repair is needed.

For machine-generated JSON that has this issue, trace the generation path back to the code that writes the output. The fix is almost always to replace manual string building or JavaScript template literals with a call to JSON.stringify. In Python, the equivalent fix is to replace manual dict-to-string conversion with json.dumps. Once the generator uses a proper serializer, every future output will have correctly quoted keys without any manual intervention.

Transforming JavaScript object literals to JSON

For a JavaScript object defined in source code, the simplest transformation is JSON.stringify(myObject, null, 2). This serializes the object with two-space indentation and produces fully spec-compliant JSON with double-quoted keys and double-quoted string values. The null second argument means no replacer is used, so all values are serialized as-is. This one-line fix works in Node.js, browsers, and any JavaScript environment.

For hand-written JSON files that need to be corrected — where you have text with unquoted keys and need to produce valid JSON — a regex-based transformation works for simple cases. The pattern /([{,]\s*)(\w+)(\s*:)/g matches an unquoted key (a word character sequence) preceded by either an opening brace or a comma and followed by a colon, and replaces it with the same key wrapped in double quotes. In JavaScript: jsonText.replace(/([{,]\s*)(\w+)(\s*:)/g, '$1"$2"$3'). This quick fix works for simple keys composed of letters, digits, and underscores, but it fails for keys containing hyphens, spaces, or special characters.

For Python code that serializes dictionaries, replace any string concatenation or f-string JSON generation with import json and json.dumps(myDict, indent=2). Python's json module is part of the standard library, handles all escaping and quoting correctly, and works identically to JSON.stringify from a compliance perspective. The key difference is that Python's True and False become JSON's true and false, and Python's None becomes JSON's null, which json.dumps handles automatically.

For API testing tools like Postman, Insomnia, or cURL, paste JSON into the body field rather than JavaScript object notation. If the tool has a 'JSON' body type selector, use it — some tools auto-add the Content-Type header and may attempt to validate the body as JSON before sending. Writing the body as valid JSON from the start prevents parsing errors on both the client tool side and the server side.

JSON5 versus standard JSON for developer configs

JSON5 is a superset of JSON that extends the format with several JavaScript-inspired features: unquoted keys that are valid ECMAScript 5 identifiers, single-quoted strings, trailing commas in arrays and objects, and single-line and multi-line comments. It was created specifically for human-written configuration files where the strictness of JSON is a usability obstacle. JSON5 is available as an npm package (json5), and several popular tools use it for their configuration files.

The critical distinction is that JSON5 is not interoperable with standard JSON parsers. If you write a .json5 file and pass it to any code that calls JSON.parse, parsing will fail on the first unquoted key. JSON5 requires its own parser. Some projects use .jsonc files (JSON with comments) or .json5 files with specific tooling support, but when the file extension is .json, the parser is almost always the standard JSON.parse with no tolerance for unquoted keys.

Popular tools that accept JSON5 or JSON-with-comments include VS Code's settings.json, TypeScript's tsconfig.json, and Prettier's configuration files. These tools use their own parsers that extend standard JSON parsing. When you copy configuration from these files and use it as a JSON payload in an API call or pass it to JSON.parse directly, it fails because those extensions are not standard JSON.

The practical rule is: if humans are writing or reading the file and it does not need to be consumed by a general-purpose JSON parser, JSON5 or JSONC is a better format than standard JSON. If the file is consumed by application code, API endpoints, or configuration loaders that use JSON.parse, use standard JSON with double-quoted keys. Keep both use cases clearly separated in your project structure and document which format each configuration file uses.

When regex quoting breaks hyphenated key names

The regex approach for adding quotes to unquoted keys — replacing word characters before a colon with quoted versions — has a significant limitation: it only handles keys that consist entirely of word characters (letters, digits, and underscores). Keys that contain hyphens, like content-type, max-age, or my-config-key, are not matched by \w+ because the hyphen is not a word character.

In JavaScript object literal syntax, a hyphenated key requires quotes even in a JavaScript object: { 'content-type': 'application/json' } — you cannot write { content-type: 'application/json' } because the hyphen would be interpreted as a subtraction operator. So if the input is valid JavaScript, hyphenated keys are already quoted and the regex handles them correctly (it does not need to match them because they already have quotes). But if the input was generated by a tool that uses hyphens in unquoted keys — which is possible in some serialization systems — the regex will fail silently by not quoting those keys.

The regex also fails for keys that start with a digit (like 0foo) or contain unicode letters that are not ASCII. These are edge cases in practice but important to know about when using regex-based transformation. A production-grade transformation should use a proper parser — either a JSON5 parser that can read the input, or a custom tokenizer that handles all valid JavaScript identifier forms.

Another common mistake is applying the regex to the entire JSON text, including string values that happen to contain patterns that look like unquoted keys. For example, a string value that contains the substring name: would be incorrectly modified by the regex. A correct transformation must understand the JSON structure — specifically, it must only apply the key-quoting transformation to the member portion of an object, not to string values. This is difficult to do correctly with a simple regex and is another reason why using a parser is the right approach for any non-trivial transformation.

Linting JSON files to catch unquoted keys early

The cheapest way to prevent unquoted key errors is to catch them during development rather than at runtime. Several tools integrate JSON validation into the development workflow and report errors at the file level before code is run.

ESLint with the eslint-plugin-json or eslint-plugin-jsonc plugin validates JSON files as part of the normal lint pass. Configure it to run on all .json files in the project. When a developer saves a JSON file with unquoted keys, the linter reports the error in the editor immediately rather than waiting for a runtime failure. The plugin integrates with most editors through the ESLint extension, providing inline error highlighting.

VS Code's built-in JSON language server validates .json files against the JSON grammar and highlights syntax errors including unquoted keys in real time. The distinction between .json (strict JSON) and .jsonc (JSON with comments) files controls which rules apply — .json files are validated strictly, while .jsonc files allow comments. Consistently using .json for files that must be parsed by JSON.parse and .jsonc or .json5 for human-written configs prevents the format confusion that leads to this error.

For CI pipelines, add a JSON validation step that runs python -m json.tool on all JSON files or uses jq . to test parsing. A command like find . -name '*.json' -not -path './node_modules/*' | xargs -I{} python -m json.tool {} will fail the CI build if any JSON file in the project has a syntax error, including unquoted keys. This check is fast, requires no additional dependencies beyond Python, and runs in seconds even for projects with hundreds of JSON files.

For teams migrating from JavaScript object notation to JSON in configuration files, a one-time transformation script is more reliable than manual editing. Write a Node.js script that requires or evaluates each JavaScript config file, then calls JSON.stringify to produce a correct JSON version, and writes the result to a new file with the .json extension. This approach handles all edge cases automatically — hyphenated keys that were already quoted, number keys, nested objects — because JSON.stringify processes the runtime object rather than the source text.

Quick fix checklist

  • Wrap every object key in double quotes — not single quotes, not unquoted identifiers
  • Replace single-quoted string values with double-quoted ones throughout the JSON
  • Pass JavaScript objects through JSON.stringify to produce correctly quoted JSON automatically
  • Use json.dumps in Python to serialize dicts to JSON rather than converting to string manually
  • Replace .json extension files that use JSON5 syntax with .json5 or .jsonc and use appropriate parsers
  • Add eslint-plugin-json to your project to catch unquoted keys during development
  • Run python -m json.tool or jq . on all JSON files in CI to catch syntax errors before deployment
  • Avoid regex-based key quoting for keys that may contain hyphens or non-ASCII characters — use a parser instead

Related guides

Frequently asked questions

Why does JavaScript allow unquoted keys but JSON does not?

JavaScript object literal syntax evolved to be convenient for developers writing code by hand, so unquoted identifier names are allowed as property names. JSON was designed as a language-independent data interchange format and intentionally simplifies the grammar by requiring all keys to be quoted strings. This makes JSON parsers simpler to implement in any language, removes ambiguity about valid identifier characters, and avoids issues with reserved words as key names.

What error does JSON.parse throw for unquoted keys?

V8 (Node.js and Chrome) throws 'SyntaxError: Unexpected token [character] in JSON at position N' where the character is the first letter of the unquoted key and N is its position in the string. Firefox throws 'SyntaxError: JSON.parse: expected property name or } at line N column M'. Both mean the parser expected a double-quote character to start a key string and found an unquoted identifier instead.

Can I use JSON.stringify to convert JavaScript objects to JSON automatically?

Yes. JSON.stringify always produces double-quoted keys and double-quoted string values, regardless of how the source object was created. Pass any JavaScript object to JSON.stringify and the result is valid JSON. Use null as the second argument (no replacer) and 2 as the third argument for readable indented output. The only cases where JSON.stringify fails are when the object contains circular references, BigInt values, or non-serializable types like functions.

What is JSON5 and when should I use it?

JSON5 is a superset of JSON that allows unquoted keys, single-quoted strings, trailing commas, and comments. It uses its own npm package (json5) and its own file extension (.json5). Use JSON5 for human-authored configuration files where readability matters more than interoperability. Use standard JSON for any file that will be parsed by JSON.parse, consumed by an API, or shared across different systems and languages.

Does a regex reliably fix unquoted keys in JSON?

Simple regex approaches work for keys made entirely of letters, digits, and underscores. They fail for hyphenated keys like content-type, keys starting with digits, and keys containing Unicode characters outside the ASCII range. The regex can also incorrectly modify patterns inside string values that look like unquoted keys. For reliable transformation, use a JSON5 parser to read the input and JSON.stringify to write the output.

Why does tsconfig.json allow unquoted keys if JSON does not?

TypeScript's tsconfig.json uses a JSON-with-comments parser (JSONC) rather than standard JSON.parse. This parser accepts both unquoted keys and comments as extensions to the JSON grammar. When you copy content from tsconfig.json and use it in a context that calls standard JSON.parse — like an API body or a configuration file parsed by your application — it fails because standard JSON.parse does not support those extensions.

How do I fix unquoted keys in a large JSON file quickly?

If the file is otherwise valid JavaScript object notation, read it with a JSON5 parser (npm install json5, then JSONbig.parse or JSON5.parse) and immediately write it back with JSON.stringify(parsed, null, 2). This correctly handles all key forms including hyphenated keys, and the resulting file is fully valid JSON. For files that are pure JSON with just the occasional missing quote, a validator will show the positions so you can fix them manually.

Is there a VS Code extension that prevents unquoted keys in JSON files?

VS Code's built-in JSON language server validates .json files in real time and highlights unquoted keys as syntax errors. No extension is required for basic validation. The ESLint extension with eslint-plugin-json or eslint-plugin-jsonc adds project-level linting that catches JSON errors during save and in CI, which is useful for ensuring consistency across a team when multiple developers edit the same JSON files.

Can Python dictionaries be used as JSON without conversion?

No. Python dict literals use the same unquoted-key syntax as JavaScript in some interpretations, and Python's True, False, and None map to JSON's true, false, and null — but with different capitalization. Always use json.dumps(myDict) to serialize a Python dictionary to JSON. The json module handles key quoting, boolean mapping, None-to-null conversion, and all other Python-to-JSON type conversions correctly.

All tools run in your browser. Your data never leaves your device. Last updated: 2026-05-05.