Why Does My JSON Have Backslashes? — How to Fix Double-Escaped JSON

Seeing "{"name":"Alice"}" instead of {"name":"Alice"}? Your JSON is double-escaped — the JSON has been serialized twice. This is one of the most common API bugs encountered by developers, especially when connecting frontend applications to backend APIs. This guide explains exactly why it happens, how to diagnose it quickly, and how to fix it permanently at the source — or work around it client-side when you can't.

Double-encode

JSON serialized twice — the most common cause

JSON.parse()

parses the outer string to get the real object

Back-end bug

usually caused by calling JSON.stringify() twice

API response

fix by removing extra serialization at source

1

What Does Double-Escaped JSON Look Like?

The difference between normal JSON and double-escaped JSON is subtle but critical. When you look at a raw API response or log it to your console, the format reveals the problem immediately.

Visual comparison

Normal JSON: {"name":"Alice","age":30} — parses to an object.
Double-escaped: "{"name":"Alice","age":30}" — parses to a string.
The outer quotes make the entire payload a JSON string containing escaped JSON. Parsing once gives you a string. You must parse a second time to get the actual object.

The telltale signs of double-escaped JSON are: the response body starts and ends with a double quote character, every internal quote is preceded by a backslash (\"), and typeof response === 'string' in JavaScript when you expected an object. In Postman or Chrome DevTools, the Response tab will show the entire body as a quoted string.

What you see vs what you expect

Expected: {"name":"Alice","age":30} — object with .name property Received: "{"name":"Alice","age":30}" — a string that contains JSON
2

Root Cause: JSON.stringify() Called Twice in JavaScript

The overwhelming majority of double-escaped JSON issues trace back to a single mistake: calling JSON.stringify() on a value that is already a JSON string, or using a framework method that performs automatic serialization on data you've already serialized.

The double-stringify mistake in Node.js

JSON.stringify() called on already-stringified value

❌ Bad
// Backend code — accidentally serializing twice
const user = { name: "Alice", age: 30 };

// First serialization — produces a string
const jsonString = JSON.stringify(user);
// jsonString = '{"name":"Alice","age":30}'

// Second serialization ❌ — serializing the string again
res.json(JSON.stringify(jsonString));
// Client receives: '"{\"name\":\"Alice\"}"'
// Because res.json() runs JSON.stringify() internally,
// wrapping your already-stringified string in another layer of quotes

Use res.json(object) OR res.send(string) — never both

✅ Good
// Option 1: Pass the object directly to res.json()
// res.json() handles all serialization automatically
const user = { name: "Alice", age: 30 };
res.json(user);  // ✅ Correct — serialized exactly once

// Option 2: If you must build the string manually and send it raw
const jsonString = JSON.stringify(user);
res.setHeader('Content-Type', 'application/json');
res.send(jsonString);  // ✅ send the raw string (already valid JSON)
// Do NOT call res.json() when data is already a string
3

Root Cause: Python Flask and Django Double Serialization

Python web frameworks have the same trap. The jsonify() function in Flask andJsonResponse in Django both serialize your data automatically. Passing an already-serialized string to them results in double encoding.

Python Flask double serialization

json.dumps() + jsonify() = double serialized

❌ Bad
import json
from flask import jsonify

user = {"name": "Alice", "age": 30}

# Manually serialize first
json_string = json.dumps(user)          # → '{"name": "Alice", "age": 30}'

# Then pass the string to jsonify ❌
# jsonify() calls json.dumps() on the string again!
return jsonify(json_string)
# Response body: '"{\"name\": \"Alice\", \"age\": 30}"'

Pass a dict to jsonify() OR use Response() with raw string

✅ Good
from flask import jsonify, Response
import json

user = {"name": "Alice", "age": 30}

# Option 1: Pass dict directly to jsonify ✅
return jsonify(user)

# Option 2: Return raw JSON string with explicit content-type ✅
json_string = json.dumps(user)
return Response(json_string, mimetype='application/json')
4

AWS Lambda and API Gateway Double Encoding

AWS API Gateway is a particularly common source of double-escaped JSON because it can apply its own serialization to Lambda return values. Understanding the flow helps you identify where the extra encoding is introduced.

How Lambda + API Gateway interacts

Lambda returns a JavaScript object. API Gateway serializes it based on the Integration Response settings. If your Lambda function returns an already-serialized JSON string instead of an object, API Gateway may serialize it again.

The Lambda handler mistake

Returning JSON.stringify(data) from a Lambda handler instead of returning data directly causes API Gateway to treat the string as a regular string value and wrap it in additional serialization.

Lambda Proxy Integration

When using Lambda Proxy Integration, the body field of the response object should be a string. But if you're also wrapping this in JSON.stringify(), the body becomes double-encoded.

Content Handling setting

API Gateway has a "Content Handling" option in integration responses. If set to "Convert to text," it may apply additional encoding. Check this setting and the mapping templates if double encoding persists.

javascriptCorrect AWS Lambda handler — return object, not string
// ❌ Common mistake — returns double-encoded JSON
exports.handler = async (event) => {
  const data = { name: "Alice", age: 30 };
  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(JSON.stringify(data))  // ❌ double stringify
  };
};

// ✅ Correct — stringify the body once
exports.handler = async (event) => {
  const data = { name: "Alice", age: 30 };
  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)  // ✅ stringify exactly once for the body field
  };
};
5

Client-Side Fix — Parse Twice When You Can't Fix the Server

Sometimes you're consuming a third-party API or legacy service that you can't modify. In that case, you need to handle double-encoded responses client-side. The approach is straightforward: detect whether the parsed value is a string, and if so, parse again.

javascriptHandle double-encoded JSON client-side
// When you receive double-escaped JSON and can't fix the server
const response = await fetch('/api/user');
const data = await response.json();

// data might be a string instead of an object due to double encoding
if (typeof data === 'string') {
  const actualData = JSON.parse(data);  // parse the inner JSON
  console.log(actualData.name);  // "Alice"
} else {
  console.log(data.name);  // already an object — normal case
}

// Generic helper to safely unwrap potentially double-encoded JSON
function unwrapJson(data) {
  if (typeof data === 'string') {
    try {
      return JSON.parse(data);
    } catch {
      return data;  // not JSON, return the string as-is
    }
  }
  return data;
}

// Usage
const raw = await response.json();
const result = unwrapJson(raw);
// result is always an object (or primitive), never a JSON string

Identify the encoding layer using curl

Run curl -v https://your-api.com/endpoint and look at the raw response body. If the body starts with " and contains \" throughout, it's double-encoded. Compare with your framework's output directly (bypass the framework and return raw) to isolate which layer adds the extra encoding.
6

Diagnosing Where the Double Encoding Happens

1

Check the raw API response

Use curl or Postman to see the raw HTTP response body. If it starts with a quote character, it's double-encoded. This rules out client-side parsing issues.

2

Add logging at the serialization point

Log the value just before sending the response on the server. If the logged value already contains escaped quotes, the serialization is happening upstream — in middleware or a data access layer.

3

Check middleware stack

Many Express/Fastify middleware components serialize responses automatically. If you have JSON serialization middleware AND you call res.json(), you get double encoding. Audit your middleware pipeline.

4

Test framework defaults

Create a minimal test endpoint that returns a hardcoded object with res.json(). Compare its output format to the problematic endpoint. If the minimal endpoint works correctly, the issue is in your data handling code, not the framework.

5

Check ORM and database layers

Some ORM libraries return stringified JSON for JSON/JSONB database columns. If your database stores {"name":"Alice"} in a JSON column and your ORM returns it as a string, then calling JSON.stringify() on that string double-encodes it.

Frequently Asked Questions