Nested JSON Escaping: Backslashes and Parsing
A payload such as {"payload":"{\"name\":\"Tiny\"}"} usually does not indicate broken escaping. It means JSON text has been stored inside another JSON string. Every string-syntax boundary must escape quotes and backslashes again. This article focuses on representation layers, not general JSON syntax or Unicode escape semantics.
1. Distinguish values, JSON text, and source literals
The same data can be an in-memory object, JSON.stringify output, or a JavaScript string literal that represents that output. The visible slash count depends on which layer a tool is showing.
Check typeof, length, and direct console output rather than relying only on an inspector preview.
const value = { message: 'He said "hello"', path: 'C:\\temp\\a.txt' };
const jsonText = JSON.stringify(value);
console.log(typeof value); // object
console.log(typeof jsonText); // string
console.log(jsonText);2. More layers require more escaping
If an outer payload field stores inner JSON text, stringify the inner object and then stringify the outer object. The second serialization protects the quotes and backslashes inside the embedded text. Those extra characters belong to the current representation, not the final business value.
const payloadObject = { name: 'Tiny', path: 'C:\\temp\\a.txt' };
const envelopeObject = {
event: 'save',
payload: JSON.stringify(payloadObject),
};
const requestBody = JSON.stringify(envelopeObject);
console.log(requestBody);3. Parse exactly once per documented string layer
Parse the outer request first. The payload remains a string until the contract says it contains serialized JSON. Do not repeatedly parse every string until parsing fails; ordinary user text such as “123” or “true” can also be valid JSON and would silently change type.
type Envelope = { event: string; payload: string };
type Payload = { name: string; path: string };
const requestBody = JSON.stringify({
event: 'save',
payload: JSON.stringify({ name: 'Tiny', path: 'C:\\temp\\a.txt' }),
});
const outer = JSON.parse(requestBody) as Envelope;
const inner = JSON.parse(outer.payload) as Payload;
console.log(inner.path); // C:\\temp\\a.txt4. Serialize objects instead of concatenating JSON
Manual concatenation breaks on quotes, backslashes, line breaks, and control characters. Construct values as objects and let JSON.stringify escape each layer.
For APIs you control, prefer a nested object over a stringified payload. Keep double encoding only when a queue field, database text column, signature format, or third-party contract requires it.
const payload = { query: 'name = "Tiny"', path: 'C:\\data' };
const preferredBody = JSON.stringify({ event: 'search', payload });
const legacyBody = JSON.stringify({
event: 'search',
payload: JSON.stringify(payload),
});5. Use field-specific compatibility parsing
If a legacy field may be either an object or a JSON object string, normalize that field once at the boundary and validate the result shape. Do not recursively inspect every string in the response.
type JsonObject = Record<string, unknown>;
function parseObjectField(value: unknown): JsonObject {
if (value && typeof value === 'object' && !Array.isArray(value)) {
return value as JsonObject;
}
if (typeof value !== 'string') {
throw new TypeError('payload must be an object or JSON object text');
}
const parsed: unknown = JSON.parse(value);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new TypeError('payload JSON must contain an object');
}
return parsed as JsonObject;
}6. Why global backslash replacement corrupts data
Removing every backslash damages Windows paths, regex text, newline sequences, and legitimate literal backslashes. Replacing escaped quotes without knowing the current layer is equally unsafe. Preserve the raw text and use the workflow in /articles/json-unexpected-token when parsing fails.
- Do not remove all backslashes.
- Do not repeatedly JSON.parse every string.
- Do not infer a JSON object only because text starts with
{. - Do not confuse an inspector preview with the network payload.
7. Boundaries and verification
Test quotes, backslashes, line breaks, tabs, empty strings, null, arrays, and Unicode. Success means the restored value deep-equals the original value, not that a log appears to contain fewer slashes.
For signed or hashed protocols, define which exact representation is signed. Object semantics, inner JSON text, and outer request bytes are different inputs.
const original = {
quote: '"',
slash: '\\',
newline: '\n',
nested: { text: '中文 🚀' },
};
const text = JSON.stringify({ payload: JSON.stringify(original) });
const outer = JSON.parse(text) as { payload: string };
const restored = JSON.parse(outer.payload);
console.assert(JSON.stringify(restored) === JSON.stringify(original));8. FAQ and conclusion
Why do Postman, Network, and console show different slash counts? They may show bytes, JSON text, or an escaped debugger preview.
Can payload always be an object? Usually for your own API, but some storage and third-party contracts require text.
Is \u4e2d the same problem? Not necessarily; it is a JSON Unicode escape covered by /articles/unicode-json-escapes.
The rule is one stringify per encoded layer and one parse per documented string layer. Avoid extra stringification when an object can be transmitted directly, and use /tools/json/json-compress-escape to inspect representation changes.
Sources and further reading
Specifications and references for checking the article’s technical details.
Related articles
JSON over HTTP: Choosing Gzip, Brotli, and Streaming
Separate JSON minification and escaping from HTTP Content-Encoding, then choose Gzip, Brotli, pagination, or NDJSON with a verifiable browser streaming example.
PitfallsLarge JSON Integers: Precision Fixes
Learn why JavaScript can round valid JSON integers, and how string contracts, BigInt conversion, and safe serialization preserve every digit.
TroubleshootingJSON.parse Unexpected Token: Debugging Causes
Debug JSON.parse errors by checking raw responses, positions, and grammar. Covers HTML, double parsing, trailing commas, escaping, and truncated data.
Keep exploring
Use the related browser tool to test the workflow with your own sample data.
Open related tool