SyntaxError: Single Quotes Are Not Valid in JSON

Quick answer

💡JSON requires double quotes for both keys and string values, per RFC 8259. Single quotes cause a SyntaxError at parse time. The most common source is Python's dict repr output or copy-pasted JavaScript object literals. Fix by running the data through a proper serializer: json.dumps() in Python or JSON.stringify() in JavaScript.

Error symptoms

  • SyntaxError: Unexpected token ' in JSON at position 0
  • SyntaxError: Unexpected token ' in JSON at position N where N is the location of the first single-quoted key or value
  • JSON parse error: expected double-quote but found single-quote
  • Python's json.loads() raises json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes
  • An online JSON validator highlights the entire first string as invalid
  • A webhook payload that looks valid in a text editor fails when passed to JSON.parse in the receiving system

Common causes

  • Copying the output of Python's print(dict) or repr(dict) which uses single quotes for string values
  • Writing JSON by hand in a text editor and using single quotes because they are easier to type without pressing Shift
  • Pasting a JavaScript object literal directly into a system that expects valid JSON, since JS objects allow single-quoted keys and values
  • A configuration file parser that is more lenient than the JSON specification accepting single-quoted values during development
  • Template literal output in JavaScript where single-quoted strings are concatenated and the result is expected to be valid JSON
  • A third-party service returning non-standard JSON with single-quoted strings that worked during testing but breaks in production

When it happens

  • When a developer copies a Python dictionary from a REPL session and pastes it into a JSON config file or API request body
  • When a configuration management tool stores JSON-like data using single quotes because the format is not strictly validated at write time
  • When a JavaScript developer writes test fixtures by hand using single quotes for convenience and the test data is later parsed as JSON
  • When a shell script uses echo or printf to construct JSON strings and single-quoting is used to avoid shell expansion
  • When a data pipeline receives data from a system that produces Python-style serialized objects instead of proper JSON

Examples and fixes

Python's default string representation of dictionaries uses single quotes around string keys and values. This output looks like JSON to the human eye but is rejected by every standard JSON parser.

Python dict output pasted as JSON causes a parse error

❌ Wrong

# Python dict output (from print(my_dict) or repr(my_dict))
# {'user_id': 'acc_8821', 'display_name': 'Jordan Ellis', 'is_active': True}

# Attempting to parse this as JSON in JavaScript:
const rawOutput = "{'user_id': 'acc_8821', 'display_name': 'Jordan Ellis', 'is_active': True}";

try {
  const parsed = JSON.parse(rawOutput);
  console.log(parsed.user_id);
} catch (err) {
  console.error(err.message);
  // SyntaxError: Unexpected token ' in JSON at position 0
}

✅ Fixed

# In Python, use json.dumps() to produce valid JSON instead of relying on repr()
import json

user_data = {
    'user_id': 'acc_8821',
    'display_name': 'Jordan Ellis',
    'is_active': True
}

# json.dumps converts Python True to JSON true and uses double quotes
valid_json_string = json.dumps(user_data)
print(valid_json_string)
# Output: {"user_id": "acc_8821", "display_name": "Jordan Ellis", "is_active": true}

# Now safe to send over HTTP or write to a file
with open('user_data.json', 'w') as f:
    json.dump(user_data, f, indent=2)

Python's dict repr uses single quotes for string values and capitalizes booleans as True and False, both of which are invalid JSON. The json.dumps function in Python's standard library produces properly formatted JSON with double-quoted strings and lowercase booleans. The broken code tried to parse Python repr output as JSON, which fails at the very first character. The fixed code uses json.dumps at the source of the data, guaranteeing that the output is valid JSON before it is sent anywhere. For writing JSON to files, json.dump with an indent parameter produces human-readable output with consistent double-quote formatting.

Developers writing JSON by hand sometimes use single quotes out of habit from JavaScript. Even though JavaScript's object literal syntax allows single quotes, the JSON specification does not, and parsers will reject single-quoted strings.

Hand-written JSON with single quotes fails in any parser

❌ Wrong

// This looks valid in a JavaScript context but is NOT valid JSON
const configText = `{
  'apiBaseUrl': 'https://api.example.com/v2',
  'timeout': 5000,
  'retryCount': 3,
  'authHeader': 'Bearer token_abc123',
  'environment': 'production'
}`;

// Fails in any strict JSON parser
const config = JSON.parse(configText);
console.log(config.apiBaseUrl);

✅ Fixed

// Valid JSON requires double quotes for all keys and string values
const configText = `{
  "apiBaseUrl": "https://api.example.com/v2",
  "timeout": 5000,
  "retryCount": 3,
  "authHeader": "Bearer token_abc123",
  "environment": "production"
}`;

// Parses successfully
const config = JSON.parse(configText);
console.log(config.apiBaseUrl);
// Output: https://api.example.com/v2
console.log(config.timeout);
// Output: 5000

The broken version uses JavaScript template literal syntax to build a string that uses single quotes around keys and values. While this is valid JavaScript object literal syntax when used as code, it is not valid JSON when treated as a string. The JSON parser sees the single quote character and throws immediately because it expects a double quote to begin a string. The fixed version changes all quotes to double quotes. Note that numeric values like 5000 and 3 remain unquoted because JSON numbers do not use quote characters. The only values that require double quotes in JSON are strings.

RFC 8259 mandates double-quote delimiters for JSON strings

The formal grammar of JSON is defined in RFC 8259, published by the Internet Engineering Task Force. The grammar rule for a JSON string is explicit: a string begins with a quotation mark character, which is Unicode code point U+0022, followed by any sequence of valid characters, followed by another quotation mark. The character U+0022 is the ASCII double quote. There is no provision in the grammar for single quotes, curly apostrophes, backtick characters, or any other delimiter. The RFC treats these as invalid characters at the start of a string value, which causes the parser to raise a syntax error immediately upon encountering them.

This strictness is intentional. JSON was designed to be simple enough that any programmer could implement a correct parser in an afternoon, and to be unambiguous enough that two different implementations would always produce identical results when parsing the same input. Allowing single quotes as an alternative string delimiter would complicate the grammar and introduce edge cases around strings that contain both single and double quotes, or strings where one type of quote is used as an apostrophe.

The confusion most often arises because JavaScript, the language that inspired JSON's syntax, allows single quotes, double quotes, and backticks as string delimiters in object literals. A JavaScript object literal is source code, subject to the JavaScript parser's rules. A JSON document is a data interchange format, subject to RFC 8259's rules. These two contexts look similar on screen but are parsed by entirely different mechanisms with entirely different rules.

Python adds a further layer of confusion because Python's default string representation for dictionaries uses single quotes. When a Python developer prints a dictionary or calls repr() on one, the output uses single-quoted strings even for values that do not contain any quote characters. This output looks almost identical to JSON and will pass a casual visual inspection, but it fails any standards-compliant JSON parser. Python's own json module handles this correctly because json.dumps always produces double-quoted output, but developers sometimes bypass the json module by using str() or repr() for quick debugging and then accidentally treat that output as JSON.

A third source of single-quoted JSON is manual construction using shell scripts or string concatenation. Shell scripting often uses single quotes to avoid variable expansion, and a script that builds a JSON string by concatenating shell variables will naturally produce single-quoted output if the author is not careful about the quoting context. The correct approach in shell scripts is to use a JSON-generation tool like jq or to use a proper programming language for JSON construction rather than raw string manipulation.

Tracing single quotes back to their original source

The error message from a JSON parser points directly to the problem: the position in the string where the unexpected character was encountered. For single-quote errors, the position is typically zero or close to the beginning of the string, because the very first key in a JSON object is usually a string that begins with a quote character. If the parser sees a single quote where it expected a double quote, it reports the error at that position.

To find the source of the single-quoted JSON, trace backward from where the parsing error occurs. If the JSON came from a network request, log the raw request body before parsing. If it came from a file, open the file in a hex editor or a text editor with visible character mode to confirm what quote characters are actually present. Visually, single quotes and double quotes are similar in many monospace fonts, particularly at small sizes, so confirming by character code rather than visual inspection is more reliable.

If the JSON came from Python code in another part of the system, look for any code that calls str(), repr(), or print() on a dictionary or object and then passes the result to another function expecting JSON. Any use of these methods to serialize data rather than json.dumps is a potential source of single-quoted strings. A static code analysis pass looking for calls to json.loads or json.parse that receive the output of str() or repr() will surface these patterns quickly in a large codebase.

For JSON that comes from external APIs or third-party services, the issue is harder to fix at the source. In this case, the receiving end must either preprocess the input to replace single quotes with double quotes before parsing, or use a more lenient parser that accepts non-standard JSON. Both approaches carry risks: preprocessing with simple string replacement can corrupt strings that contain apostrophes or intentional single quotes, and lenient parsers may accept other non-standard constructs that later cause issues when the data is re-serialized to strict JSON. The cleanest long-term solution is to contact the API provider and request that they fix their output to comply with RFC 8259.

Converting Python dict output and other sources to valid JSON

The safest and most reliable fix in every language is to use the official JSON serialization library rather than relying on language-specific string representations. In Python, this means replacing any use of str(data) or repr(data) with json.dumps(data). The json.dumps function handles all the necessary transformations: it converts Python's True and False to JSON's lowercase true and false, converts Python's None to JSON's null, and uses double quotes for all string values. For more complex objects, the default parameter allows customizing how non-serializable types are converted.

In JavaScript, replacing manually constructed JSON strings with JSON.stringify ensures correct output. JSON.stringify handles escaping of special characters within strings, converts dates, and produces valid JSON regardless of what the original JavaScript string delimiters were. If a JavaScript object was written using single-quoted string values and then converted to a JSON string, JSON.stringify will produce properly double-quoted JSON output because it operates on the parsed values, not on the source code syntax.

When you receive single-quoted JSON from an external source that cannot be fixed, a preprocessing step is necessary. A naive approach is to call replace("'", '"') on the raw string, but this breaks strings that contain apostrophes. The word it's, for example, would become it"s after a blind replacement, producing invalid JSON. A slightly better approach is to use a regular expression that replaces single quotes only when they appear at the start or end of a value position, but these patterns quickly become complex enough to fail on edge cases.

The most robust preprocessing approach for Python-repr-style input is to use Python's ast.literal_eval function, which safely evaluates a string containing a Python literal expression and returns the corresponding Python object. Since Python's repr output is a valid Python literal, ast.literal_eval can parse it correctly, including handling apostrophes and escaped characters correctly. The result is a Python dict that can then be serialized with json.dumps to produce valid JSON. This approach is safe because ast.literal_eval does not execute arbitrary code and raises ValueError for any input that is not a recognized Python literal.

For shell scripts, the canonical fix is to use jq for JSON construction. The jq command-line tool can build JSON from shell variables using --arg and --argjson parameters, which handle quoting and escaping automatically. Alternatively, using Python as a one-liner to construct JSON from shell variables is reliable and avoids the quoting complexities of shell-native JSON construction.

When JSON5 is the appropriate alternative format

JSON5 is a separate data format, not a version of JSON, that extends the JSON syntax to include several conveniences from JavaScript's ES5 object literal syntax. Among the extensions JSON5 supports is the use of single quotes as string delimiters. JSON5 also supports trailing commas in objects and arrays, unquoted keys that are valid JavaScript identifiers, comments, and multi-line strings. If the data you are working with uses single quotes along with these other extensions, it may be intentionally formatted as JSON5 rather than JSON.

The distinction matters because a JSON5 file should not be parsed with a JSON parser, and a JSON file should not need a JSON5 parser to be read correctly. If you are consuming JSON5 from a configuration file or a data source that uses the .json5 file extension, use a JSON5 parsing library rather than trying to preprocess the input to remove single quotes. Libraries like json5 in Node.js and json5 in Python handle the full JSON5 grammar correctly.

JSON5 is popular in configuration files, particularly in JavaScript projects where configuration authors are more comfortable with JavaScript syntax than strict JSON. Babel configuration files use JSON5, and some tools like ESLint configuration files accept JSON5 syntax. However, it is important not to use JSON5 in API response bodies or anywhere that the consumer is expected to use a standard JSON parser, because most JSON parsers do not accept JSON5 syntax.

If you are building a tool that accepts configuration files, consider whether your users would benefit from JSON5's leniency. Allowing single quotes, trailing commas, and comments in configuration files significantly reduces the friction of hand-editing configuration. Just be explicit in your documentation about whether the format is JSON or JSON5, and use the appropriate parser accordingly. Mixing JSON and JSON5 in the same project without clear labeling is a common source of confusion.

JSONC, which stands for JSON with Comments, is another variant that allows C-style comments inside JSON documents but still requires double quotes for strings. JSONC is used by TypeScript's tsconfig.json and VS Code's settings.json. If your tool uses JSONC, single quotes are still not valid, and the only extension over standard JSON is the permission to use line comments and block comments.

The apostrophe replacement trap in single-quote fixes

The most tempting quick fix for a single-quote JSON error is to replace every single quote in the string with a double quote. This approach seems obvious and works for simple cases where the JSON values contain no apostrophes. For real-world data, it almost always produces incorrect output because natural language text frequently contains apostrophes in contractions and possessives.

Consider a JSON-like string with the value 'The user\'s profile data'. After blind replacement of single quotes with double quotes, this becomes "The user"s profile data", which breaks the JSON structure because the double quote after user terminates the string prematurely. The remainder of the string, s profile data, appears outside the string value and causes a parse error.

A second trap is assuming that the single-quote problem is limited to the outermost string delimiters. Python's repr output sometimes escapes internal single quotes with a backslash, as in 'The user\'s data'. When you replace the outer single quotes with double quotes, the internal escaped single quote becomes \' which is not a valid JSON escape sequence. JSON's string escape sequences are specific: backslash followed by one of double quote, backslash, forward slash, b, f, n, r, t, or a u followed by four hex digits. A backslash followed by a single quote is not a valid JSON escape and will cause a parse error.

A related mistake is using a regular expression replacement that looks for quoted strings in the Python-repr format. These regular expressions tend to fail on edge cases involving strings that contain the delimiter character, strings with backslash sequences, or strings that span multiple lines in Python's repr output. Regular expression parsing of quoted strings is a known hard problem in computer science, and any regex-based approach will have blind spots for adversarial or simply unusual inputs.

The reliable way to avoid the apostrophe trap is to use a proper language parser to interpret the source format, not a text manipulation tool. Python's ast.literal_eval parses Python repr output correctly regardless of apostrophes or escape sequences. For JavaScript object literals, a full JavaScript parser like Babel or acorn can parse the object and then JSON.stringify can re-serialize it correctly. These tools understand the escaping rules of the source format and handle all edge cases that string replacement misses.

Enforcing double-quote style across development pipelines

Preventing single-quote JSON errors is significantly easier than debugging them after they reach production. A combination of linting, schema validation, and serialization discipline can eliminate this class of error from a project entirely.

For JavaScript and TypeScript projects, configuring Prettier with the singleQuote option set to false ensures that all code files use double quotes. While this affects JavaScript code rather than JSON data files, it creates a consistent mental model where developers expect double quotes in both contexts. ESLint's quotes rule can enforce the same convention for files that are not processed by Prettier. For JSON data files specifically, the jsonc-eslint-parser and eslint-plugin-jsonc plugins can lint JSON files with ESLint rules, catching syntax errors and style issues before they reach a parser.

For API endpoint testing, including a step that parses every API response body through a strict JSON parser before examining the content will catch single-quote errors and other malformed JSON before they reach the business logic layer. In an Express.js or Fastify application, middleware that calls JSON.parse on the raw request body and returns 400 Bad Request for any parse error prevents single-quoted JSON from propagating into the application. Most frameworks apply this parsing automatically when the Content-Type is application/json, but adding explicit error handling for the parse step makes the failure mode visible rather than silently swallowing malformed input.

For data pipelines that receive input from multiple sources including Python services, establish a contract at the boundary where data enters the pipeline: all JSON must be validated by a JSON Schema validator before processing. A validator like ajv in Node.js or jsonschema in Python will reject any input that is not well-formed JSON, including single-quoted strings. Combining schema validation with schema-defined types means that the error message describes not just that the JSON is malformed but also which field and which type constraint failed, making debugging faster.

For configuration files that are edited by hand, choosing a format that is more forgiving than strict JSON reduces the operational burden without sacrificing correctness. TOML is strongly typed, human-readable, and does not require quotes around most string values. YAML allows both single and double quoted strings. JSON5 allows single quotes. Any of these formats can be compiled to JSON for consumption by tools that require it, with the compilation step serving as a validation checkpoint that catches quoting errors at build time rather than at runtime.

Quick fix checklist

  • Identify the source of the single-quoted JSON: Python repr output, manual writing, or a third-party API
  • Use json.dumps() in Python instead of str() or repr() to serialize dictionaries to JSON
  • Use JSON.stringify() in JavaScript instead of manually constructing JSON strings with concatenation
  • For Python repr input, use ast.literal_eval() to parse it, then json.dumps() to re-serialize
  • Avoid blind single-to-double-quote replacement because it breaks strings containing apostrophes
  • If single quotes are intentional, check whether the format is actually JSON5 and use a JSON5 parser
  • Add JSON.parse or json.loads at API boundaries to catch malformed JSON before it reaches business logic
  • Add a JSON linter or schema validator to your CI pipeline to catch format errors before deployment

Related guides

Frequently asked questions

Why does JSON require double quotes instead of allowing single quotes?

RFC 8259, the JSON specification, defines a string as a sequence of Unicode characters delimited by double-quote characters, specifically the quotation-mark character at Unicode code point U+0022. The spec allows only one delimiter type to keep the grammar unambiguous and simple. Single quotes, backticks, and other quote-like characters are all invalid string delimiters in strict JSON, even though JavaScript itself accepts single-quoted strings in object literals.

Python's dict output uses single quotes. How do I get valid JSON from Python?

Use the json.dumps function from Python's standard library rather than str() or repr(). json.dumps(my_dict) returns a properly formatted JSON string with double-quoted keys and values, lowercase booleans, and null for None values. For writing to a file, use json.dump(my_dict, file_handle, indent=2) to produce readable, indented JSON. Never use print(dict) or repr(dict) output as JSON data.

Can I use a regular expression to replace single quotes with double quotes?

Only for the simplest cases where no string value contains apostrophes or escape sequences. A regex replacement fails on strings like 'don't' because replacing the outer single quotes with double quotes leaves an unescaped double quote in the middle of the string, breaking the JSON structure. Use Python's ast.literal_eval followed by json.dumps for Python repr output, or a full language parser for JavaScript object literals.

Is JSON5 a version of JSON that allows single quotes?

JSON5 is a separate format inspired by JavaScript ES5 syntax, not a version or superset of JSON. It allows single quotes, trailing commas, unquoted keys, and comments. Valid JSON is also valid JSON5, but valid JSON5 is not necessarily valid JSON. Use the json5 npm package or a dedicated JSON5 library to parse JSON5 files rather than a standard JSON parser.

What is the error position number in the single-quote SyntaxError message?

The position number in SyntaxError: Unexpected token ' in JSON at position N refers to the character index in the JSON string where the parser encountered the invalid character, with zero as the index of the first character. Position 0 means the very first character is wrong, which happens when the JSON starts with a single-quoted key like {'key': 'value'}. Higher positions point further into the string where the first invalid character appears.

Does VS Code or any editor warn me about single quotes in JSON files?

VS Code has built-in JSON language support that validates JSON files with the .json extension and highlights syntax errors including single quotes. The JSON extension uses the same strict JSON grammar as JSON.parse. For .jsonc files (JSON with Comments), VS Code uses a slightly more lenient parser that accepts comments but still rejects single quotes. Installing the ESLint extension with jsonc-eslint-parser enables additional rule-based linting for JSON and JSONC files.

Can I configure JSON.parse to accept single quotes?

No, JSON.parse implements the strict JSON specification and cannot be configured to accept non-standard syntax. If you need to parse JSON with single quotes, use a third-party library that implements a lenient JSON parser, such as json5 for JSON5 syntax or hjson for the Hjson format. Be aware that using a lenient parser means your codebase depends on non-standard formatting that other tools in your pipeline may reject.

How do I find all places in my codebase where single-quoted JSON might be produced?

Search for calls to str(), repr(), or print() on dictionary or object variables that are then passed to a function expecting a JSON string. In Python, look for json.loads or json.load calls that receive the output of string formatting operations. In JavaScript, search for places where template literals or string concatenation build JSON-like strings with single-quoted values. Code review checklists should include verifying that all JSON serialization goes through json.dumps or JSON.stringify.

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