[{"data":1,"prerenderedAt":3359},["ShallowReactive",2],{"blog-list-en-3":3},[4,1014,2229],{"id":5,"title":6,"author":7,"body":8,"category":991,"date":992,"description":993,"draft":994,"extension":995,"h1":15,"image":996,"lastmod":992,"locales":997,"meta":999,"navigation":1000,"path":1001,"promo":1002,"seo":1006,"stem":1007,"tags":1008,"__hash__":1013},"blog\u002Fen\u002Fblog\u002Funexpected-end-of-json-input.md","Unexpected End of JSON Input: Causes and Fixes","JSON Toolbox Team",{"type":9,"value":10,"toc":958},"minimark",[11,16,27,36,47,62,70,75,86,89,97,104,109,117,123,134,157,161,324,350,354,357,361,368,374,378,384,394,398,401,407,480,484,490,493,497,503,509,513,520,526,529,569,572,576,579,585,590,596,599,605,611,615,618,626,643,663,667,670,688,691,707,716,719,723,728,762,767,798,802,805,810,814,817,821,827,831,834,838,857,861,868,872,882,886,889,896,913,917],[12,13,15],"h1",{"id":14},"unexpected-end-of-json-input-what-it-means-and-how-to-fix-it","Unexpected End of JSON Input: What It Means and How to Fix It",[17,18,24],"pre",{"className":19,"code":21,"language":22,"meta":23},[20],"language-text","SyntaxError: Unexpected end of JSON input\n    at JSON.parse (\u003Canonymous>)\n","text","",[25,26,21],"code",{"__ignoreMap":23},[28,29,30,31,35],"p",{},"This error says one thing: ",[32,33,34],"strong",{},"the parser reached the end of the string while it was still expecting more."," It never found the closing piece it needed, so it gave up at the last character.",[28,37,38,39,42,43,46],{},"The useful part is that the message narrows the cause considerably. An empty API response, a truncated download, and a missing ",[25,40,41],{},"}"," are three different problems that need three different fixes — and on modern JavaScript engines they do not even produce the same message. This guide shows how to tell them apart in about a minute, and how to fix each one in ",[25,44,45],{},"fetch()",", Node.js, React, and file reads.",[48,49,50],"blockquote",{},[28,51,52,55,56,61],{},[32,53,54],{},"Paste it and see where it breaks:"," the ",[57,58,60],"a",{"href":59},"\u002Ftools\u002Fformat\u002Fjson-repair","JSON Repair"," tool fixes missing brackets, trailing commas, and quoting problems in your browser, and reports an error instead of guessing when a document cannot be recovered.",[28,63,64,65,69],{},"For the wider picture — ten parse errors, not just this one — see ",[57,66,68],{"href":67},"\u002Fblog\u002Fjson-parse-error-debug","JSON Parse Failed: 10 Common API Errors and How to Debug Them",".",[71,72,74],"h2",{"id":73},"what-does-unexpected-end-of-json-input-mean","What does \"Unexpected end of JSON input\" mean?",[28,76,77,85],{},[57,78,82],{"href":79,"rel":80},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FJSON\u002Fparse",[81],"nofollow",[25,83,84],{},"JSON.parse()"," reads a string and expects exactly one complete JSON value. If the string ends before that value is finished, parsing fails.",[28,87,88],{},"On current V8 (Node 20+, Chrome, Edge), these all produce the message:",[17,90,95],{"className":91,"code":93,"language":94,"meta":23},[92],"language-js","JSON.parse('')        \u002F\u002F SyntaxError: Unexpected end of JSON input\nJSON.parse('   ')     \u002F\u002F SyntaxError: Unexpected end of JSON input\nJSON.parse('[1,')     \u002F\u002F SyntaxError: Unexpected end of JSON input\nJSON.parse('{\"a\":')   \u002F\u002F SyntaxError: Unexpected end of JSON input\nJSON.parse('tru')     \u002F\u002F SyntaxError: Unexpected end of JSON input\n","js",[25,96,93],{"__ignoreMap":23},[28,98,99,100,103],{},"The pattern: in every case the parser was ",[32,101,102],{},"expecting a value"," and the input ran out — the string was empty, it was only whitespace, or it ended right after a comma, a colon, or mid-literal.",[105,106,108],"h3",{"id":107},"when-you-get-a-different-message-instead","When you get a different message instead",[28,110,111,112,116],{},"A document that is cut off ",[113,114,115],"em",{},"after"," a complete value produces a different, more specific error with a position:",[17,118,121],{"className":119,"code":120,"language":94,"meta":23},[92],"JSON.parse('{\"a\": 1')      \u002F\u002F SyntaxError: Expected ',' or '}' after property value in JSON at position 7\nJSON.parse('[1, 2')        \u002F\u002F SyntaxError: Expected ',' or ']' after array element in JSON at position 5\nJSON.parse('{\"a\": \"bc')    \u002F\u002F SyntaxError: Unterminated string in JSON at position 9\nJSON.parse('{\"a\":1,')      \u002F\u002F SyntaxError: Expected double-quoted property name in JSON at position 7\n",[25,122,120],{"__ignoreMap":23},[28,124,125,126,129,130,133],{},"So if you are looking at exactly ",[25,127,128],{},"Unexpected end of JSON input"," on a current engine, suspect ",[32,131,132],{},"empty input"," first, not a missing brace. Two caveats:",[135,136,137,148],"ul",{},[138,139,140,143,144,147],"li",{},[32,141,142],{},"Older engines differ."," Before V8's improved JSON errors, a truncated document like ",[25,145,146],{},"{\"a\": 1"," also reported \"Unexpected end of JSON input\". If you are on an older runtime or see this message in a library's logs, a missing bracket is still a candidate.",[138,149,150,153,154,69],{},[32,151,152],{},"Other engines word it differently."," Firefox reports its own message, along the lines of ",[25,155,156],{},"JSON.parse: unexpected end of data at line 1 column 1",[71,158,160],{"id":159},"common-causes-at-a-glance","Common causes at a glance",[162,163,164,180],"table",{},[165,166,167],"thead",{},[168,169,170,174,177],"tr",{},[171,172,173],"th",{},"Cause",[171,175,176],{},"Typical symptom",[171,178,179],{},"How to confirm",[181,182,183,210,236,253,291,304],"tbody",{},[168,184,185,191,204],{},[186,187,188],"td",{},[32,189,190],{},"Empty response body",[186,192,193,196,197,200,201],{},[25,194,195],{},"204 No Content",", or an endpoint that returns nothing after a successful ",[25,198,199],{},"DELETE","\u002F",[25,202,203],{},"POST",[186,205,206,209],{},[25,207,208],{},"text.length === 0","; status is 204\u002F205",[168,211,212,217,227],{},[186,213,214],{},[32,215,216],{},"Whitespace-only body",[186,218,219,220,223,224],{},"Body is ",[25,221,222],{},"\" \""," or ",[25,225,226],{},"\"\\n\"",[186,228,229,232,233],{},[25,230,231],{},"text.trim().length === 0"," but ",[25,234,235],{},"text.length > 0",[168,237,238,243,246],{},[186,239,240],{},[32,241,242],{},"Truncated response",[186,244,245],{},"Timeout, proxy buffer limit, body-size cap killed the transfer",[186,247,248,249,252],{},"Received bytes \u003C ",[25,250,251],{},"Content-Length","; ends mid-value",[168,254,255,260,273],{},[186,256,257],{},[32,258,259],{},"Unclosed structure in hand-written JSON",[186,261,262,263,265,266,269,270],{},"Missing ",[25,264,41],{},", ",[25,267,268],{},"]",", or closing ",[25,271,272],{},"\"",[186,274,275,276,265,279,265,282,265,284,287,288],{},"Ends with ",[25,277,278],{},"{",[25,280,281],{},"[",[25,283,272],{},[25,285,286],{},",",", or ",[25,289,290],{},":",[168,292,293,298,301],{},[186,294,295],{},[32,296,297],{},"File read before the write finished",[186,299,300],{},"Non-atomic write, or reading a streamed file too early",[186,302,303],{},"Retry the read and it works; file grows between reads",[168,305,306,314,317],{},[186,307,308],{},[32,309,310,311],{},"Parsing ",[25,312,313],{},"undefined",[186,315,316],{},"Value came from a missing variable or an unset field",[186,318,319,320,323],{},"Message is ",[25,321,322],{},"\"undefined\" is not valid JSON",", not this one",[28,325,326,327,330,331,334,335,338,339,342,343,345,346,349],{},"One counter-intuitive case worth knowing: ",[25,328,329],{},"JSON.parse(null)"," does ",[32,332,333],{},"not"," throw — ",[25,336,337],{},"null"," is coerced to the string ",[25,340,341],{},"\"null\""," and parses to ",[25,344,337],{},". ",[25,347,348],{},"JSON.parse(undefined)"," throws, but with a different message.",[71,351,353],{"id":352},"how-to-debug-empty-vs-truncated-vs-unclosed","How to debug: empty vs truncated vs unclosed",[28,355,356],{},"Work through these in order. Each step eliminates one of the three causes.",[105,358,360],{"id":359},"step-1-read-the-text-not-the-parsed-value","Step 1: Read the text, not the parsed value",[28,362,363,364,367],{},"Never debug this error through ",[25,365,366],{},"res.json()"," — it parses before you can look at anything. Read the body as text first:",[17,369,372],{"className":370,"code":371,"language":94,"meta":23},[92],"const res = await fetch(url)\nconst text = await res.text()\nconsole.log('status:', res.status, '| length:', text.length)\n",[25,373,371],{"__ignoreMap":23},[105,375,377],{"id":376},"step-2-is-it-empty","Step 2: Is it empty?",[17,379,382],{"className":380,"code":381,"language":94,"meta":23},[92],"if (text.trim().length === 0) {\n  \u002F\u002F Empty or whitespace-only: this is the classic cause of the message.\n  console.log('empty body, status', res.status)\n}\n",[25,383,381],{"__ignoreMap":23},[28,385,386,389,390,393],{},[25,387,388],{},"length === 0"," means no body at all. ",[25,391,392],{},"trim().length === 0"," with a non-zero length means whitespace only — a surprisingly common outcome when a server writes a newline.",[105,395,397],{"id":396},"step-3-inspect-the-tail","Step 3: Inspect the tail",[28,399,400],{},"The last characters tell you which failure you have:",[17,402,405],{"className":403,"code":404,"language":94,"meta":23},[92],"console.log(JSON.stringify(text.slice(-80)))\n",[25,406,404],{"__ignoreMap":23},[162,408,409,419],{},[165,410,411],{},[168,412,413,416],{},[171,414,415],{},"Ends with",[171,417,418],{},"What it means",[181,420,421,432,443,454,466],{},[168,422,423,429],{},[186,424,425,265,427],{},[25,426,278],{},[25,428,281],{},[186,430,431],{},"The structure was opened and never closed",[168,433,434,440],{},[186,435,436,439],{},[25,437,438],{},"\"a"," (an odd number of unescaped quotes)",[186,441,442],{},"A string was left unterminated",[168,444,445,451],{},[186,446,447,223,449],{},[25,448,286],{},[25,450,290],{},[186,452,453],{},"A value was expected and never arrived",[168,455,456,459],{},[186,457,458],{},"A complete value but no closing bracket",[186,460,262,461,223,463,465],{},[25,462,41],{},[25,464,268],{}," — usually a different error message with a position",[168,467,468,477],{},[186,469,470,471,223,474],{},"Mid-token, e.g. ",[25,472,473],{},"tru",[25,475,476],{},"12.",[186,478,479],{},"The document was cut off mid-value",[105,481,483],{"id":482},"step-4-compare-received-bytes-with-content-length","Step 4: Compare received bytes with Content-Length",[17,485,488],{"className":486,"code":487,"language":94,"meta":23},[92],"const declared = res.headers.get('content-length')\nconsole.log('declared:', declared, '| received:', new TextEncoder().encode(text).length)\n",[25,489,487],{"__ignoreMap":23},[28,491,492],{},"If you received fewer bytes than declared, the response was truncated in transit — a timeout, a proxy buffer limit, or a body-size cap. Re-fetch; do not try to parse half a document.",[105,494,496],{"id":495},"step-5-classify-it-automatically","Step 5: Classify it automatically",[28,498,499,500,502],{},"Run this only after ",[25,501,84],{}," has already failed — it classifies the tail of a broken string, it does not tell you whether a document is valid.",[17,504,507],{"className":505,"code":506,"language":94,"meta":23},[92],"function inspectJsonFailure(text) {\n  const trimmed = text.trim()\n\n  if (trimmed.length === 0) {\n    return { kind: 'empty', detail: 'The input is empty or whitespace only.' }\n  }\n\n  const last = trimmed[trimmed.length - 1]\n  if ('{[\",:'.includes(last)) {\n    return { kind: 'unclosed', detail: `Input ends with \"${last}\" — a value or closing bracket is missing.` }\n  }\n\n  return { kind: 'truncated', detail: 'Input ends mid-value. Compare received bytes with Content-Length.' }\n}\n",[25,508,506],{"__ignoreMap":23},[71,510,512],{"id":511},"how-to-fix-it-in-fetch","How to fix it in fetch()",[28,514,515,516,519],{},"The fix is to stop calling ",[25,517,518],{},".json()"," blindly. Read the text, handle the empty case, check the content type, then parse:",[17,521,524],{"className":522,"code":523,"language":94,"meta":23},[92],"async function fetchJson(url, init) {\n  const res = await fetch(url, init)\n  const text = await res.text()\n\n  \u002F\u002F 204 No Content and 205 Reset Content have no body by definition.\n  if (res.status === 204 || res.status === 205 || text.trim() === '') {\n    return null\n  }\n\n  const type = res.headers.get('content-type') || ''\n  if (!type.includes('application\u002Fjson')) {\n    throw new Error(`Expected JSON from ${url}, got \"${type || 'no content-type'}\"`)\n  }\n\n  try {\n    return JSON.parse(text)\n  } catch (err) {\n    throw new Error(`Invalid JSON from ${url} (${text.length} bytes): ${err.message}`)\n  }\n}\n",[25,525,523],{"__ignoreMap":23},[28,527,528],{},"Three details that matter:",[530,531,532,554,563],"ol",{},[138,533,534,542,543,545,546,553],{},[32,535,536,539,540],{},[25,537,538],{},"res.text()"," then ",[25,541,84],{},", not ",[25,544,366],{},". You cannot inspect a body you already parsed — and ",[57,547,550],{"href":548,"rel":549},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FResponse\u002Fjson",[81],[25,551,552],{},"Response.json()"," throws before you get a chance.",[138,555,556,559,560,562],{},[32,557,558],{},"A 204 is a success."," Do not treat it as an error; return ",[25,561,337],{}," (or whatever your code uses for \"no content\").",[138,564,565,568],{},[32,566,567],{},"Check the content type."," An HTML error page from a proxy returns 200 and parses as neither JSON nor an empty string — it fails with a different message, and this check makes the real problem obvious.",[28,570,571],{},"For truncated responses, the fix is not parsing: it is raising timeouts, lifting proxy body limits, or paginating the endpoint.",[71,573,575],{"id":574},"how-to-fix-it-in-nodejs","How to fix it in Node.js",[28,577,578],{},"Reading a file:",[17,580,583],{"className":581,"code":582,"language":94,"meta":23},[92],"import { readFile } from 'node:fs\u002Fpromises'\n\nconst text = await readFile('data.json', 'utf8')\n\nif (text.trim() === '') {\n  throw new Error('data.json is empty — the write did not complete')\n}\n\nconst data = JSON.parse(text)\n",[25,584,582],{"__ignoreMap":23},[28,586,587,588,290],{},"Parsing a request body — note that an empty body arrives as an empty string, not as ",[25,589,313],{},[17,591,594],{"className":592,"code":593,"language":94,"meta":23},[92],"\u002F\u002F Express\napp.post('\u002Fwebhook', express.json(), (req, res) => {\n  \u002F\u002F req.body is {} when the body is empty, not undefined\n  if (!req.body || Object.keys(req.body).length === 0) {\n    return res.status(400).json({ error: 'EMPTY_BODY' })\n  }\n  \u002F\u002F ...\n})\n",[25,595,593],{"__ignoreMap":23},[28,597,598],{},"Reading JSON that another process is still writing is the subtle version of this bug. Write atomically so a reader never sees a half-written file:",[17,600,603],{"className":601,"code":602,"language":94,"meta":23},[92],"import { writeFile, rename } from 'node:fs\u002Fpromises'\n\nconst target = 'data.json'\nconst tmp = `${target}.tmp`\n\nawait writeFile(tmp, JSON.stringify(data, null, 2), 'utf8')\nawait rename(tmp, target) \u002F\u002F atomic on the same filesystem\n",[25,604,602],{"__ignoreMap":23},[28,606,607,610],{},[25,608,609],{},"rename"," is atomic within a filesystem, so a concurrent reader sees either the old file or the new one — never a partial one.",[71,612,614],{"id":613},"how-to-fix-it-in-react-and-other-frontend-code","How to fix it in React and other frontend code",[28,616,617],{},"The usual cause in a component is parsing during the first render, before data exists — or parsing an empty response from an endpoint that returns nothing:",[17,619,624],{"className":620,"code":622,"language":623,"meta":23},[621],"language-jsx","function ItemList() {\n  const [items, setItems] = useState([])\n  const [error, setError] = useState(null)\n\n  useEffect(() => {\n    let cancelled = false\n\n    ;(async () => {\n      try {\n        const res = await fetch('\u002Fapi\u002Fitems')\n        const text = await res.text()\n\n        if (cancelled) return\n\n        if (text.trim() === '') {\n          setItems([])          \u002F\u002F no content is a valid outcome, not an error\n          return\n        }\n\n        setItems(JSON.parse(text))\n      } catch (err) {\n        if (!cancelled) setError(err)\n      }\n    })()\n\n    return () => { cancelled = true }\n  }, [])\n\n  if (error) return \u003Cp>Failed to load: {error.message}\u003C\u002Fp>\n  return \u003Cul>{items.map((i) => \u003Cli key={i.id}>{i.name}\u003C\u002Fli>)}\u003C\u002Ful>\n}\n","jsx",[25,625,622],{"__ignoreMap":23},[28,627,628,629,638,639,642],{},"Two habits prevent most of these: ",[32,630,631,632,635,636],{},"never call ",[25,633,634],{},"JSON.parse"," on a value that might be ",[25,637,313],{},", and ",[32,640,641],{},"never parse during render"," — parse inside the effect or the loader, after you have confirmed the text exists.",[28,644,645,646,649,650,653,654,656,657,659,660,662],{},"If the JSON comes from ",[25,647,648],{},"localStorage",", the same rule applies: ",[25,651,652],{},"localStorage.getItem(key)"," returns ",[25,655,337],{}," when the key is missing, and ",[25,658,329],{}," quietly returns ",[25,661,337],{}," instead of the object you expected.",[71,664,666],{"id":665},"validate-and-repair-the-json-in-your-browser","Validate and repair the JSON in your browser",[28,668,669],{},"When you have the text in front of you, two tools finish the job:",[28,671,672,676,677,680,681,223,684,687],{},[32,673,674],{},[57,675,60],{"href":59}," — fixes trailing commas, single quotes, unquoted keys, ",[32,678,679],{},"missing closing brackets",", comments, and Python\u002FJS constants such as ",[25,682,683],{},"True",[25,685,686],{},"NaN",". It applies best-effort fixes, then parses the result to confirm it is valid before showing it.",[28,689,690],{},"Two limits to keep in mind, both stated on the tool page:",[135,692,693,700],{},[138,694,695,696,699],{},"It ",[32,697,698],{},"cannot invent missing data",". Closing a bracket is recoverable; a document whose middle was cut off is not.",[138,701,702,703,706],{},"If the structure cannot be recovered, it ",[32,704,705],{},"reports an error instead of returning partial output",". That is the correct outcome for a truncated response — get the full data instead.",[28,708,709,715],{},[32,710,711],{},[57,712,714],{"href":713},"\u002Ftools\u002Fformat\u002Fjson-editor","JSON Editor"," — paste or open the file to get live syntax validation with the error position, then format or minify. Use it to confirm a hand-written file is complete before your application reads it.",[28,717,718],{},"Both run in your browser, so the payload is not uploaded — which matters when the broken JSON is a production API response.",[71,720,722],{"id":721},"how-to-prevent-the-error","How to prevent the error",[28,724,725],{},[32,726,727],{},"Server side:",[135,729,730,740,750,756],{},[138,731,732,735,736,739],{},[32,733,734],{},"Always return valid JSON, including errors."," ",[25,737,738],{},"{\"error\": {...}}"," is far easier to debug than an empty 500.",[138,741,742,749],{},[32,743,744,745,748],{},"Do not set ",[25,746,747],{},"Content-Type: application\u002Fjson"," on a 204."," If there is no body, say so with the status code and no content type.",[138,751,752,755],{},[32,753,754],{},"Set explicit timeouts and body-size limits"," so a truncation fails loudly with a status code instead of silently cutting a document in half.",[138,757,758,761],{},[32,759,760],{},"Write files atomically"," (temp file + rename) so no reader ever sees a partial file.",[28,763,764],{},[32,765,766],{},"Client side:",[135,768,769,777,786,792],{},[138,770,771,735,774,69],{},[32,772,773],{},"Guard before parsing:",[25,775,776],{},"if (text && text.trim() !== '') { JSON.parse(text) }",[138,778,779,785],{},[32,780,781,782,784],{},"Wrap ",[25,783,84],{}," in try\u002Fcatch"," and include the length and the tail of the string in the error message — that is the information you will need later.",[138,787,788,791],{},[32,789,790],{},"Treat \"no content\" as a normal outcome"," for endpoints that can legitimately return nothing.",[138,793,794,797],{},[32,795,796],{},"Log the offending payload safely:"," log length, status, and a truncated tail, not the whole body, which may contain tokens or personal data.",[71,799,801],{"id":800},"faq","FAQ",[105,803,74],{"id":804},"what-does-unexpected-end-of-json-input-mean-1",[28,806,807,809],{},[25,808,84],{}," reached the end of the string while still expecting more content. On current engines that most often means the input was empty or whitespace-only, or ended right after a comma, colon, or mid-literal.",[105,811,813],{"id":812},"is-this-error-always-caused-by-an-empty-response","Is this error always caused by an empty response?",[28,815,816],{},"No, but on modern V8 an empty or whitespace-only string is the most common cause of this exact wording. A document with a missing closing bracket usually produces a different message that includes a character position — unless you are on an older engine, which reported the same message for both.",[105,818,820],{"id":819},"how-do-i-know-if-the-response-is-truncated","How do I know if the response is truncated?",[28,822,823,824,826],{},"Compare the bytes you received with the ",[25,825,251],{}," header, and look at the last ~80 characters. If the document stops mid-value, or you received fewer bytes than declared, it was truncated — re-fetch rather than trying to parse it.",[105,828,830],{"id":829},"can-this-error-happen-with-otherwise-valid-json","Can this error happen with otherwise valid JSON?",[28,832,833],{},"Yes — if only part of a valid document arrived. A 400 KB response cut off at 300 KB is \"valid JSON\" that was never fully delivered. The other case is a file you read while it was still being written.",[105,835,837],{"id":836},"how-do-i-fix-it-in-fetch","How do I fix it in fetch?",[28,839,840,841,843,844,846,847,265,850,853,854,856],{},"Do not call ",[25,842,366],{}," directly. Read ",[25,845,538],{},", return early for ",[25,848,849],{},"204",[25,851,852],{},"205",", or an empty body, verify the content type, then ",[25,855,84],{}," inside a try\u002Fcatch that reports the length and tail of the text.",[105,858,860],{"id":859},"how-do-i-fix-it-in-react","How do I fix it in React?",[28,862,863,864,867],{},"Parse inside the effect or loader, not during render, and only after confirming the text exists. Handle the empty-body case explicitly instead of letting ",[25,865,866],{},"JSON.parse('')"," throw on every render.",[105,869,871],{"id":870},"how-do-i-fix-it-in-nodejs","How do I fix it in Node.js?",[28,873,874,875,878,879,881],{},"Check for an empty string after ",[25,876,877],{},"fs.readFile",", and write files atomically (temp file + ",[25,880,609],{},") so a concurrent read never sees half a file.",[105,883,885],{"id":884},"can-an-online-tool-repair-truncated-json","Can an online tool repair truncated JSON?",[28,887,888],{},"It can repair documents with recoverable syntax problems — missing closing brackets, trailing commas, quoting issues. It cannot restore data that never arrived. For a truncated response, re-fetch from the source.",[105,890,892,893,895],{"id":891},"why-does-jsonparsenull-not-throw","Why does ",[25,894,329],{}," not throw?",[28,897,898,899,338,901,903,904,906,907,909,910,912],{},"Because ",[25,900,337],{},[25,902,341],{},", which is valid JSON. It returns ",[25,905,337],{},". This silently masks missing values, so check for ",[25,908,337],{}," before parsing values from ",[25,911,648],{}," or optional fields.",[71,914,916],{"id":915},"whats-next","What's Next?",[135,918,919,927,935,943],{},[138,920,921,924,925,69],{},[32,922,923],{},"Have the broken text?"," Paste it into ",[57,926,60],{"href":59},[138,928,929,932,933,69],{},[32,930,931],{},"Need the error position?"," Validate it in the ",[57,934,714],{"href":713},[138,936,937,940,941,69],{},[32,938,939],{},"Other parse errors?"," Read ",[57,942,68],{"href":67},[138,944,945,948,949,953,954,69],{},[32,946,947],{},"Suspect the file itself?"," See ",[57,950,952],{"href":951},"\u002Fblog\u002Fhow-to-open-json-file","How to Open, View, and Edit a JSON File"," and ",[57,955,957],{"href":956},"\u002Fblog\u002Fhow-to-create-json-file","How to Create a JSON File",{"title":23,"searchDepth":959,"depth":959,"links":960},2,[961,965,966,973,974,975,976,977,978,990],{"id":73,"depth":959,"text":74,"children":962},[963],{"id":107,"depth":964,"text":108},3,{"id":159,"depth":959,"text":160},{"id":352,"depth":959,"text":353,"children":967},[968,969,970,971,972],{"id":359,"depth":964,"text":360},{"id":376,"depth":964,"text":377},{"id":396,"depth":964,"text":397},{"id":482,"depth":964,"text":483},{"id":495,"depth":964,"text":496},{"id":511,"depth":959,"text":512},{"id":574,"depth":959,"text":575},{"id":613,"depth":959,"text":614},{"id":665,"depth":959,"text":666},{"id":721,"depth":959,"text":722},{"id":800,"depth":959,"text":801,"children":979},[980,981,982,983,984,985,986,987,988],{"id":804,"depth":964,"text":74},{"id":812,"depth":964,"text":813},{"id":819,"depth":964,"text":820},{"id":829,"depth":964,"text":830},{"id":836,"depth":964,"text":837},{"id":859,"depth":964,"text":860},{"id":870,"depth":964,"text":871},{"id":884,"depth":964,"text":885},{"id":891,"depth":964,"text":989},"Why does JSON.parse(null) not throw?",{"id":915,"depth":959,"text":916},"json_tools","2026-10-04T00:00:00.000Z","Unexpected end of JSON input: the parser ran out of text too early. Diagnose empty, truncated, or unclosed JSON, then fix it in fetch, Node, and files.",false,"md","\u002Fblog\u002Fcover\u002Fen\u002Funexpected-end-of-json-input-cover.svg",[998],"en",{},true,"\u002Fen\u002Fblog\u002Funexpected-end-of-json-input",{"slug":1003,"text":1004,"btn":1005},"json-repair","Paste the broken JSON and repair it in your browser:","Open JSON Repair",{"title":6,"description":993},"en\u002Fblog\u002Funexpected-end-of-json-input",[1009,634,1010,1011,1012],"JSON","Debugging","JavaScript","API","AecV3R5yHNO1d9xSwwnz4gsfg4nZiUl8CveDlDsd3LM",{"id":1015,"title":1016,"author":7,"body":1017,"category":991,"date":2213,"description":2214,"draft":994,"extension":995,"h1":1022,"image":2215,"lastmod":2213,"locales":2216,"meta":2217,"navigation":1000,"path":2218,"promo":2219,"seo":2223,"stem":2224,"tags":2225,"__hash__":2228},"blog\u002Fen\u002Fblog\u002Fhow-to-create-manifest-json.md","How to Create a manifest.json File: PWA & Chrome Examples",{"type":9,"value":1018,"toc":2179},[1019,1023,1030,1039,1045,1049,1055,1058,1119,1122,1136,1139,1143,1152,1155,1215,1230,1236,1240,1244,1265,1269,1325,1329,1345,1349,1357,1363,1367,1370,1378,1385,1389,1396,1403,1416,1420,1556,1563,1567,1573,1600,1603,1634,1638,1642,1648,1652,1701,1705,1725,1728,1734,1748,1752,1776,1779,1783,1911,1915,1918,1927,1936,1946,1954,1957,1970,1974,1977,2022,2025,2027,2031,2044,2048,2051,2055,2071,2075,2083,2087,2096,2100,2116,2120,2130,2132,2171,2174],[12,1020,1022],{"id":1021},"how-to-create-a-manifestjson-file-pwa-and-chrome-extension-examples","How to Create a manifest.json File: PWA and Chrome Extension Examples",[28,1024,1025,1026,1029],{},"Two developers can search \"how to create a manifest.json file\" and need completely different files. One is adding install support to a website. The other is publishing a Chrome extension. Both files are named ",[25,1027,1028],{},"manifest.json",". Almost nothing else about them is the same.",[28,1031,1032,1033,1038],{},"That is the key idea: ",[32,1034,1035,1037],{},[25,1036,1028],{}," is a filename convention, not a format."," The file is ordinary JSON; what matters is the specification the consumer expects. This guide covers the two specs you are most likely to need — the W3C Web App Manifest (PWA) and the Chrome Extension Manifest V3 — with minimal working examples, the fields each one requires, and how to debug them when a browser refuses to load them.",[28,1040,1041,1042,1044],{},"If you are new to JSON files themselves, start with ",[57,1043,957],{"href":956}," for the syntax rules and saving steps, then come back here.",[71,1046,1048],{"id":1047},"what-is-a-manifestjson-file","What is a manifest.json file?",[28,1050,1051,1052,1054],{},"A ",[25,1053,1028],{}," is a JSON file that describes an application to the software that runs it: its name, icons, entry point, permissions, and display behavior.",[28,1056,1057],{},"The same filename is used by several unrelated ecosystems:",[162,1059,1060,1073],{},[165,1061,1062],{},[168,1063,1064,1067,1070],{},[171,1065,1066],{},"Kind of manifest",[171,1068,1069],{},"Who reads it",[171,1071,1072],{},"Purpose",[181,1074,1075,1086,1097,1108],{},[168,1076,1077,1080,1083],{},[186,1078,1079],{},"Web App Manifest",[186,1081,1082],{},"Browsers",[186,1084,1085],{},"Makes a site installable as a PWA",[168,1087,1088,1091,1094],{},[186,1089,1090],{},"Extension manifest",[186,1092,1093],{},"Chrome, Edge, Firefox",[186,1095,1096],{},"Declares an extension's metadata, scripts, and permissions",[168,1098,1099,1102,1105],{},[186,1100,1101],{},"Framework manifest",[186,1103,1104],{},"Next.js and similar tools",[186,1106,1107],{},"Generated or consumed by the framework",[168,1109,1110,1113,1116],{},[186,1111,1112],{},"Platform manifest",[186,1114,1115],{},"Game mods, plugins, cloud services",[186,1117,1118],{},"Platform-specific packaging metadata",[28,1120,1121],{},"Two rules hold across all of them:",[530,1123,1124,1130],{},[138,1125,1126,1129],{},[32,1127,1128],{},"The file is JSON."," No comments, no trailing commas, double-quoted keys, UTF-8. A file that is valid JSON can still be rejected, but a file that is not valid JSON is always rejected.",[138,1131,1132,1135],{},[32,1133,1134],{},"The spec decides the fields."," Copying a Chrome extension's manifest into a PWA does nothing useful — the structures are not interchangeable.",[28,1137,1138],{},"Because these files are edited by hand and read by strict parsers, the same three problems come up constantly: a trailing comma, a comment someone added for documentation, and an icon path that 404s.",[71,1140,1142],{"id":1141},"web-app-manifest-pwa-what-it-is-and-when-you-need-it","Web App Manifest (PWA): what it is and when you need it",[28,1144,1145,1146,1151],{},"The ",[57,1147,1150],{"href":1148,"rel":1149},"https:\u002F\u002Fwww.w3.org\u002FTR\u002Fappmanifest\u002F",[81],"Web Application Manifest"," is a W3C specification: a JSON file that tells the browser how your app should look and behave when installed.",[28,1153,1154],{},"It declares:",[135,1156,1157,1168,1174,1183,1204],{},[138,1158,1159,735,1162,953,1165,69],{},[32,1160,1161],{},"Identity:",[25,1163,1164],{},"name",[25,1166,1167],{},"short_name",[138,1169,1170,1173],{},[32,1171,1172],{},"Icons:"," sizes the browser uses for the home screen, taskbar, and splash screen.",[138,1175,1176,735,1179,1182],{},[32,1177,1178],{},"Entry point:",[25,1180,1181],{},"start_url"," — what opens when the app is launched.",[138,1184,1185,735,1188,1191,1192,265,1195,265,1198,287,1201,69],{},[32,1186,1187],{},"Display:",[25,1189,1190],{},"display"," — ",[25,1193,1194],{},"standalone",[25,1196,1197],{},"fullscreen",[25,1199,1200],{},"minimal-ui",[25,1202,1203],{},"browser",[138,1205,1206,735,1209,953,1212,69],{},[32,1207,1208],{},"Colors:",[25,1210,1211],{},"theme_color",[25,1213,1214],{},"background_color",[28,1216,1217,1218,1223,1224,1229],{},"You need one if you want your site to be installable — added to a phone's home screen or a desktop dock and opened in its own window instead of a browser tab. MDN's ",[57,1219,1222],{"href":1220,"rel":1221},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FManifest",[81],"Web app manifests"," guide and web.dev's ",[57,1225,1228],{"href":1226,"rel":1227},"https:\u002F\u002Fweb.dev\u002Flearn\u002Fpwa\u002Fweb-app-manifest",[81],"web app manifest"," tutorial are the reference material.",[28,1231,1232,1233,1235],{},"You do ",[32,1234,333],{}," need one for a site that should stay a website.",[71,1237,1239],{"id":1238},"how-to-create-a-manifestjson-for-a-pwa","How to create a manifest.json for a PWA",[105,1241,1243],{"id":1242},"step-1-create-the-file","Step 1: Create the file",[28,1245,1246,1247,1249,1250,1253,1254,1257,1258,1261,1262,69],{},"Create ",[25,1248,1028],{}," in your site's public root (or ",[25,1251,1252],{},"manifest.webmanifest"," — see the FAQ). For a project that serves ",[25,1255,1256],{},"public\u002F"," statically, that is ",[25,1259,1260],{},"public\u002Fmanifest.json",", which becomes ",[25,1263,1264],{},"\u002Fmanifest.json",[105,1266,1268],{"id":1267},"step-2-add-the-required-fields","Step 2: Add the required fields",[162,1270,1271,1281],{},[165,1272,1273],{},[168,1274,1275,1278],{},[171,1276,1277],{},"Field",[171,1279,1280],{},"Why it is needed",[181,1282,1283,1294,1304,1313],{},[168,1284,1285,1291],{},[186,1286,1287,223,1289],{},[25,1288,1164],{},[25,1290,1167],{},[186,1292,1293],{},"The label shown under the icon and in the install dialog",[168,1295,1296,1301],{},[186,1297,1298],{},[25,1299,1300],{},"icons",[186,1302,1303],{},"At minimum a 192px and a 512px PNG",[168,1305,1306,1310],{},[186,1307,1308],{},[25,1309,1181],{},[186,1311,1312],{},"The page that opens when the app launches",[168,1314,1315,1319],{},[186,1316,1317],{},[25,1318,1190],{},[186,1320,1321,1322,1324],{},"Whether the app gets its own window; ",[25,1323,1194],{}," is the common choice",[105,1326,1328],{"id":1327},"step-3-add-the-recommended-fields","Step 3: Add the recommended fields",[28,1330,1331,265,1334,265,1336,265,1338,638,1341,1344],{},[25,1332,1333],{},"description",[25,1335,1211],{},[25,1337,1214],{},[25,1339,1340],{},"orientation",[25,1342,1343],{},"screenshots"," improve the install experience and are quick to add.",[105,1346,1348],{"id":1347},"step-4-write-the-manifest","Step 4: Write the manifest",[17,1350,1355],{"className":1351,"code":1353,"language":1354,"meta":23},[1352],"language-json","{\n  \"name\": \"JSON Toolbox\",\n  \"short_name\": \"JSON Toolbox\",\n  \"description\": \"Free, browser-based JSON tools for developers.\",\n  \"start_url\": \"\u002F\",\n  \"scope\": \"\u002F\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\",\n  \"theme_color\": \"#0284c7\",\n  \"orientation\": \"portrait-primary\",\n  \"icons\": [\n    {\n      \"src\": \"\u002Ficons\u002Ficon-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image\u002Fpng\",\n      \"purpose\": \"any\"\n    },\n    {\n      \"src\": \"\u002Ficons\u002Ficon-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\u002Fpng\",\n      \"purpose\": \"any\"\n    },\n    {\n      \"src\": \"\u002Ficons\u002Fmaskable-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\u002Fpng\",\n      \"purpose\": \"maskable\"\n    }\n  ]\n}\n","json",[25,1356,1353],{"__ignoreMap":23},[28,1358,1359,1362],{},[25,1360,1361],{},"purpose: \"maskable\""," is optional but worth having: it tells Android the icon has safe padding, so the OS can crop it into a shape without cutting off your logo.",[105,1364,1366],{"id":1365},"step-5-link-it-from-your-html","Step 5: Link it from your HTML",[28,1368,1369],{},"The manifest does nothing until a page points at it:",[17,1371,1376],{"className":1372,"code":1374,"language":1375,"meta":23},[1373],"language-html","\u003Clink rel=\"manifest\" href=\"\u002Fmanifest.json\">\n","html",[25,1377,1374],{"__ignoreMap":23},[28,1379,1380,1381,1384],{},"Put it in the ",[25,1382,1383],{},"\u003Chead>"," of every page you want installable — or at least your entry page.",[105,1386,1388],{"id":1387},"step-6-serve-it-over-https-and-test","Step 6: Serve it over HTTPS and test",[28,1390,1391,1392,1395],{},"Browsers only offer installation in a secure context, so the manifest and the site must be served over HTTPS in production (",[25,1393,1394],{},"localhost"," counts as secure for development).",[28,1397,1398,1399,1402],{},"To verify, open DevTools → ",[32,1400,1401],{},"Application → Manifest",". Chrome shows the parsed fields, flags missing icons, and reports whether the page meets its installability criteria. That panel is far faster than guessing: it names the exact field that is missing.",[28,1404,1405,1406,223,1408,1410,1411,265,1413,1415],{},"Chrome's criteria include an HTTPS origin, a manifest with ",[25,1407,1164],{},[25,1409,1167],{},", 192px and 512px icons, ",[25,1412,1181],{},[25,1414,1190],{},", and a registered service worker with a fetch handler. The set has changed across Chrome versions, so treat the DevTools panel as the source of truth rather than any single article — including this one.",[71,1417,1419],{"id":1418},"common-mistakes-when-creating-a-pwa-manifest","Common mistakes when creating a PWA manifest",[162,1421,1422,1435],{},[165,1423,1424],{},[168,1425,1426,1429,1432],{},[171,1427,1428],{},"Symptom",[171,1430,1431],{},"Likely cause",[171,1433,1434],{},"Fix",[181,1436,1437,1451,1469,1487,1503,1518,1534],{},[168,1438,1439,1442,1445],{},[186,1440,1441],{},"\"Manifest: Line: 1, column: 1, Syntax error\"",[186,1443,1444],{},"Invalid JSON — usually a trailing comma or a comment",[186,1446,1447,1448,1450],{},"Remove it, or paste the file into ",[57,1449,60],{"href":59}," to clean it up",[168,1452,1453,1456,1463],{},[186,1454,1455],{},"DevTools shows no manifest at all",[186,1457,1458,1459,1462],{},"Missing or wrong ",[25,1460,1461],{},"\u003Clink rel=\"manifest\">"," path",[186,1464,1465,1466],{},"Use an absolute path: ",[25,1467,1468],{},"href=\"\u002Fmanifest.json\"",[168,1470,1471,1474,1481],{},[186,1472,1473],{},"Manifest fetched but not parsed",[186,1475,1476,1477,1480],{},"Server returned ",[25,1478,1479],{},"text\u002Fhtml"," — usually a 404 page or a SPA fallback",[186,1482,1483,1484,1486],{},"Make sure ",[25,1485,1264],{}," is served as JSON, not your index.html",[168,1488,1489,1492,1500],{},[186,1490,1491],{},"Install prompt never appears",[186,1493,1494,1495,200,1497,1499],{},"Missing 192px or 512px icon, missing ",[25,1496,1181],{},[25,1498,1190],{},", not HTTPS, or no service worker with a fetch handler",[186,1501,1502],{},"Check the Installability section in DevTools",[168,1504,1505,1508,1515],{},[186,1506,1507],{},"Icon looks broken or cropped",[186,1509,1510,1511,1514],{},"Wrong icon path, or no ",[25,1512,1513],{},"maskable"," icon",[186,1516,1517],{},"Use absolute paths; add a maskable icon with padding",[168,1519,1520,1523,1528],{},[186,1521,1522],{},"App opens the wrong page",[186,1524,1525,1527],{},[25,1526,1181],{}," relative to the manifest, not the HTML",[186,1529,1530,1531,1533],{},"Start it with ",[25,1532,200],{}," and confirm it resolves",[168,1535,1536,1539,1549],{},[186,1537,1538],{},"Field ignored by the browser",[186,1540,1541,1542,1545,1546,1548],{},"Typo or wrong type (",[25,1543,1544],{},"\"display\": \"Standalone\""," is not valid; use lowercase ",[25,1547,1194],{},")",[186,1550,1551,1552],{},"Compare against the ",[57,1553,1555],{"href":1148,"rel":1554},[81],"W3C spec",[28,1557,1558,1559,69],{},"One trap worth calling out: your editor may accept comments in this file because VS Code reads many config files as JSONC. The browser does not. Comments make the manifest fail to parse — see ",[57,1560,1562],{"href":1561},"\u002Fblog\u002Fjson-comments","Comments in JSON",[71,1564,1566],{"id":1565},"chrome-extension-manifestjson-what-it-is-and-when-you-need-it","Chrome extension manifest.json: what it is and when you need it",[28,1568,1569,1570,1572],{},"Every Chrome extension has a ",[25,1571,1028],{}," in its root directory. It declares the extension's name, version, icons, scripts, and permissions — without it, Chrome will not load the folder at all.",[28,1574,1575,1576,1579,1580,1583,1584,1587,1588,1592,1593,69],{},"The current standard is ",[32,1577,1578],{},"Manifest V3",". V2 extensions have been phased out, so any example showing ",[25,1581,1582],{},"\"manifest_version\": 2"," or a ",[25,1585,1586],{},"background.scripts"," array is out of date. See Chrome's ",[57,1589,1578],{"href":1590,"rel":1591},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fextensions\u002Fdevelop\u002Fmigrate\u002Fwhat-is-mv3",[81]," overview and MDN's ",[57,1594,1597,1599],{"href":1595,"rel":1596},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FMozilla\u002FAdd-ons\u002FWebExtensions\u002Fmanifest.json",[81],[25,1598,1028],{}," reference",[28,1601,1602],{},"Three V3 changes cause most migration errors:",[530,1604,1605,1618,1631],{},[138,1606,1607,1608,1611,1612,542,1615,69],{},"Background pages are ",[32,1609,1610],{},"service workers",": ",[25,1613,1614],{},"\"background\": { \"service_worker\": \"background.js\" }",[25,1616,1617],{},"\"background\": { \"scripts\": [...] }",[138,1619,1620,1621,1626,1627,1630],{},"Host access moved to ",[32,1622,1623],{},[25,1624,1625],{},"host_permissions","; ",[25,1628,1629],{},"permissions"," now holds API permissions only.",[138,1632,1633],{},"Remotely hosted code is not allowed — scripts must ship inside the extension.",[71,1635,1637],{"id":1636},"how-to-create-a-manifestjson-for-a-chrome-extension-manifest-v3","How to create a manifest.json for a Chrome extension (Manifest V3)",[105,1639,1641],{"id":1640},"step-1-create-the-file-in-the-extension-root","Step 1: Create the file in the extension root",[17,1643,1646],{"className":1644,"code":1645,"language":22,"meta":23},[20],"my-extension\u002F\n├── manifest.json\n├── background.js\n├── popup.html\n└── icons\u002F\n    ├── icon-16.png\n    ├── icon-48.png\n    └── icon-128.png\n",[25,1647,1645],{"__ignoreMap":23},[105,1649,1651],{"id":1650},"step-2-add-the-required-keys","Step 2: Add the required keys",[162,1653,1654,1664],{},[165,1655,1656],{},[168,1657,1658,1661],{},[171,1659,1660],{},"Key",[171,1662,1663],{},"Requirement",[181,1665,1666,1679,1688],{},[168,1667,1668,1673],{},[186,1669,1670],{},[25,1671,1672],{},"manifest_version",[186,1674,1675,1676],{},"Must be ",[25,1677,1678],{},"3",[168,1680,1681,1685],{},[186,1682,1683],{},[25,1684,1164],{},[186,1686,1687],{},"Display name",[168,1689,1690,1695],{},[186,1691,1692],{},[25,1693,1694],{},"version",[186,1696,1697,1698],{},"One to four dot-separated integers, e.g. ",[25,1699,1700],{},"\"1.0.0\"",[105,1702,1704],{"id":1703},"step-3-add-the-keys-most-extensions-need","Step 3: Add the keys most extensions need",[28,1706,1707,265,1709,265,1711,1714,1715,265,1718,265,1720,638,1722,69],{},[25,1708,1333],{},[25,1710,1300],{},[25,1712,1713],{},"action"," (toolbar button and popup), ",[25,1716,1717],{},"background.service_worker",[25,1719,1629],{},[25,1721,1625],{},[25,1723,1724],{},"content_scripts",[105,1726,1348],{"id":1727},"step-4-write-the-manifest-1",[17,1729,1732],{"className":1730,"code":1731,"language":1354,"meta":23},[1352],"{\n  \"manifest_version\": 3,\n  \"name\": \"My Extension\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A minimal Manifest V3 Chrome extension.\",\n  \"icons\": {\n    \"16\": \"icons\u002Ficon-16.png\",\n    \"48\": \"icons\u002Ficon-48.png\",\n    \"128\": \"icons\u002Ficon-128.png\"\n  },\n  \"action\": {\n    \"default_popup\": \"popup.html\",\n    \"default_title\": \"My Extension\",\n    \"default_icon\": {\n      \"16\": \"icons\u002Ficon-16.png\",\n      \"48\": \"icons\u002Ficon-48.png\",\n      \"128\": \"icons\u002Ficon-128.png\"\n    }\n  },\n  \"background\": {\n    \"service_worker\": \"background.js\"\n  },\n  \"permissions\": [\"storage\"],\n  \"host_permissions\": [\"https:\u002F\u002Fexample.com\u002F*\"]\n}\n",[25,1733,1731],{"__ignoreMap":23},[28,1735,1736,1737,1740,1741,542,1744,1747],{},"Note the icon keys: they are ",[32,1738,1739],{},"strings"," (",[25,1742,1743],{},"\"16\"",[25,1745,1746],{},"16","), and the paths are relative to the extension root, not the manifest.",[105,1749,1751],{"id":1750},"step-5-load-and-test-it","Step 5: Load and test it",[530,1753,1754,1760,1766,1773],{},[138,1755,1756,1757,69],{},"Open ",[25,1758,1759],{},"chrome:\u002F\u002Fextensions",[138,1761,1762,1763,69],{},"Enable ",[32,1764,1765],{},"Developer mode",[138,1767,1768,1769,1772],{},"Click ",[32,1770,1771],{},"Load unpacked"," and select your extension folder.",[138,1774,1775],{},"Read the error list on the extension's card — Chrome reports manifest problems with the key involved, and the service worker's console is reachable via the \"service worker\" link.",[28,1777,1778],{},"A manifest that is valid JSON can still be rejected here. Chrome validates the schema too: an unknown key produces a warning, and an invalid value produces an error.",[71,1780,1782],{"id":1781},"common-mistakes-when-creating-a-chrome-extension-manifest","Common mistakes when creating a Chrome extension manifest",[162,1784,1785,1796],{},[165,1786,1787],{},[168,1788,1789,1792,1794],{},[171,1790,1791],{},"Mistake",[171,1793,1428],{},[171,1795,1434],{},[181,1797,1798,1814,1831,1846,1861,1875,1886,1901],{},[168,1799,1800,1805,1808],{},[186,1801,1802,1804],{},[25,1803,1582],{}," or missing",[186,1806,1807],{},"\"Unrecognized manifest key\" \u002F refuses to load",[186,1809,1810,1811],{},"Set ",[25,1812,1813],{},"\"manifest_version\": 3",[168,1815,1816,1822,1825],{},[186,1817,262,1818,223,1820],{},[25,1819,1164],{},[25,1821,1694],{},[186,1823,1824],{},"\"Required value 'version' is missing\"",[186,1826,1827,1828,1830],{},"Add both; ",[25,1829,1694],{}," must be dot-separated integers",[168,1832,1833,1837,1840],{},[186,1834,1835],{},[25,1836,1617],{},[186,1838,1839],{},"Background never runs in V3",[186,1841,1842,1843],{},"Use ",[25,1844,1845],{},"\"service_worker\": \"background.js\"",[168,1847,1848,1853,1856],{},[186,1849,1850,1851],{},"Match patterns in ",[25,1852,1629],{},[186,1854,1855],{},"\"Permission ... is unknown or URL pattern is malformed\"",[186,1857,1858,1859],{},"Move URLs to ",[25,1860,1625],{},[168,1862,1863,1866,1869],{},[186,1864,1865],{},"Icon key is a number",[186,1867,1868],{},"Icon missing",[186,1870,1871,1872],{},"Use string keys: ",[25,1873,1874],{},"\"16\": \"icons\u002Ficon-16.png\"",[168,1876,1877,1880,1883],{},[186,1878,1879],{},"Icon file missing",[186,1881,1882],{},"\"Could not load icon\"",[186,1884,1885],{},"Verify the path relative to the extension root",[168,1887,1888,1891,1894],{},[186,1889,1890],{},"Comments in the manifest",[186,1892,1893],{},"\"Manifest is not valid JSON\"",[186,1895,1896,1897],{},"Remove them — or strip them with ",[57,1898,1900],{"href":1899},"\u002Ftools\u002Fconvert\u002Fjsonc-to-json","JSONC to JSON",[168,1902,1903,1906,1908],{},[186,1904,1905],{},"Trailing comma",[186,1907,1893],{},[186,1909,1910],{},"Remove the final comma",[71,1912,1914],{"id":1913},"write-validate-and-format-your-manifest","Write, validate, and format your manifest",[28,1916,1917],{},"Manifest files are small, hand-edited, and unforgiving. Three checks catch nearly every failure:",[28,1919,1920,1923,1924,1926],{},[32,1921,1922],{},"1. Validate the JSON first."," Paste the file into the ",[57,1925,714],{"href":713},": it highlights syntax errors as you type and can format or minify the document before you copy or download it. Because it runs in your browser, you can paste an unreleased extension manifest or an internal PWA config without sending it anywhere.",[28,1928,1929,1932,1933,1935],{},[32,1930,1931],{},"2. Repair instead of rewriting."," If the file already has trailing commas, single quotes, unquoted keys, or comments, ",[57,1934,60],{"href":59}," fixes all of them at once and returns valid JSON.",[28,1937,1938,1941,1942,1945],{},[32,1939,1940],{},"3. Check it from the command line."," On any machine with ",[25,1943,1944],{},"jq"," or Python installed:",[17,1947,1952],{"className":1948,"code":1950,"language":1951,"meta":23},[1949],"language-bash","jq . manifest.json\npython -m json.tool manifest.json\n","bash",[25,1953,1950],{"__ignoreMap":23},[28,1955,1956],{},"Both parse the file and print it, so an error means the JSON is invalid. Commands like these are also easy to add to CI so a broken manifest never reaches production.",[28,1958,1959,1960,1964,1965,1969],{},"For an extra layer, generate a JSON Schema from a known-good manifest with the ",[57,1961,1963],{"href":1962},"\u002Ftools\u002Fconvert\u002Fjson-schema-generator","JSON Schema Generator"," and validate future versions against it with the ",[57,1966,1968],{"href":1967},"\u002Ftools\u002Fformat\u002Fjson-schema-validator","JSON Schema Validator",". This catches a renamed or missing key that is still perfectly valid JSON — the class of bug syntax checking cannot see.",[71,1971,1973],{"id":1972},"other-types-of-manifestjson","Other types of manifest.json",[28,1975,1976],{},"The same filename appears in other ecosystems, each with its own required fields:",[135,1978,1979,1997,2006,2014],{},[138,1980,1981,1984,1985,223,1988,1991,1992,69],{},[32,1982,1983],{},"Next.js"," — the App Router supports ",[25,1986,1987],{},"app\u002Fmanifest.json",[25,1989,1990],{},"app\u002Fmanifest.ts"," and generates the Web App Manifest for you; see the ",[57,1993,1996],{"href":1994,"rel":1995},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Ffile-conventions\u002Fmetadata\u002Fmanifest",[81],"Next.js manifest documentation",[138,1998,1999,2002,2003,2005],{},[32,2000,2001],{},"Adobe UXP plugins"," — a ",[25,2004,1028],{}," declaring the plugin id, host application, and entry point.",[138,2007,2008,2002,2011,2013],{},[32,2009,2010],{},"Minecraft behavior and resource packs",[25,2012,1028],{}," with a header, module list, and UUIDs.",[138,2015,2016,2019,2020,69],{},[32,2017,2018],{},"Cloud and container tooling"," — various deployment descriptors also named ",[25,2021,1028],{},[28,2023,2024],{},"The pattern is always the same: the platform's documentation defines the fields, and JSON syntax is only the container. When in doubt, follow the platform's official docs over any generic tutorial — including this one.",[71,2026,801],{"id":800},[105,2028,2030],{"id":2029},"what-is-the-difference-between-manifestjson-and-manifestwebmanifest","What is the difference between manifest.json and manifest.webmanifest?",[28,2032,2033,2034,2037,2038,345,2041,2043],{},"They hold the same content. ",[25,2035,2036],{},".webmanifest"," is the extension recommended by the W3C spec, and the spec's media type is ",[25,2039,2040],{},"application\u002Fmanifest+json",[25,2042,1028],{}," is the de facto name most projects use, and browsers accept it. Pick one; make sure your server sends a JSON content type for it.",[105,2045,2047],{"id":2046},"do-i-need-a-manifestjson-for-every-website","Do I need a manifest.json for every website?",[28,2049,2050],{},"No. Add one if you want the site to be installable or to control how it looks when installed. A blog, a docs site, or a marketing page that should stay in a browser tab needs nothing.",[105,2052,2054],{"id":2053},"can-i-use-comments-in-a-manifestjson","Can I use comments in a manifest.json?",[28,2056,2057,2058,953,2061,2064,2065,2067,2068,2070],{},"Not in the file you ship. Standard JSON has no comment syntax, so ",[25,2059,2060],{},"\u002F\u002F",[25,2062,2063],{},"\u002F* *\u002F"," make the manifest invalid and both browsers and Chrome will reject it. Your editor may accept them because it reads the file as JSONC — that is the editor being lenient, not the browser. See ",[57,2066,1562],{"href":1561},", and use ",[57,2069,1900],{"href":1899}," to strip them before publishing.",[105,2072,2074],{"id":2073},"why-doesnt-my-pwa-show-the-install-prompt","Why doesn't my PWA show the install prompt?",[28,2076,2077,2078,223,2080,2082],{},"Usually one of: the manifest is missing a 192px or 512px icon, ",[25,2079,1181],{},[25,2081,1190],{}," is missing, the page is not served over HTTPS, or there is no registered service worker with a fetch handler. Open DevTools → Application → Manifest and read the installability list — it names what is missing.",[105,2084,2086],{"id":2085},"why-does-chrome-say-invalid-manifest-for-my-extension","Why does Chrome say \"Invalid manifest\" for my extension?",[28,2088,2089,2090,2092,2093,2095],{},"Either the JSON is invalid (trailing comma, comment, single quotes) or a value fails schema validation (missing ",[25,2091,1694],{},", wrong ",[25,2094,1672],{},", malformed permission). Load the extension unpacked and read the error on its card — Chrome names the offending key.",[105,2097,2099],{"id":2098},"can-i-use-the-same-manifestjson-for-a-pwa-and-a-chrome-extension","Can I use the same manifest.json for a PWA and a Chrome extension?",[28,2101,2102,2103,265,2105,638,2107,2110,2111,953,2113,2115],{},"No. They are different specifications with different required keys. ",[25,2104,1672],{},[25,2106,1629],{},[25,2108,2109],{},"background"," mean nothing to a browser reading a web app manifest, and ",[25,2112,1181],{},[25,2114,1190],{}," mean nothing to Chrome loading an extension. Keep them in separate files in separate projects.",[105,2117,2119],{"id":2118},"where-should-the-file-go","Where should the file go?",[28,2121,2122,2123,2125,2126,2129],{},"For a PWA, somewhere served at a stable public URL — commonly ",[25,2124,1264],{}," at the site root, referenced by an absolute ",[25,2127,2128],{},"href",". For a Chrome extension, the root of the extension folder, next to the scripts it references.",[71,2131,916],{"id":915},[135,2133,2134,2142,2150,2157,2164],{},[138,2135,2136,2139,2140,69],{},[32,2137,2138],{},"Writing a manifest now?"," Format and validate it in the ",[57,2141,714],{"href":713},[138,2143,2144,2147,2148,69],{},[32,2145,2146],{},"Already broken?"," Fix commas, quotes, and comments with ",[57,2149,60],{"href":59},[138,2151,2152,940,2155,69],{},[32,2153,2154],{},"New to JSON files?",[57,2156,957],{"href":956},[138,2158,2159,948,2162,69],{},[32,2160,2161],{},"Fighting comments or trailing commas?",[57,2163,1562],{"href":1561},[138,2165,2166,948,2169,69],{},[32,2167,2168],{},"Debugging a parse error?",[57,2170,68],{"href":67},[2172,2173],"hr",{},[28,2175,2176],{},[113,2177,2178],{},"All tools on JSON Toolbox run entirely in your browser. Your data never leaves your device.",{"title":23,"searchDepth":959,"depth":959,"links":2180},[2181,2182,2183,2191,2192,2193,2200,2201,2202,2203,2212],{"id":1047,"depth":959,"text":1048},{"id":1141,"depth":959,"text":1142},{"id":1238,"depth":959,"text":1239,"children":2184},[2185,2186,2187,2188,2189,2190],{"id":1242,"depth":964,"text":1243},{"id":1267,"depth":964,"text":1268},{"id":1327,"depth":964,"text":1328},{"id":1347,"depth":964,"text":1348},{"id":1365,"depth":964,"text":1366},{"id":1387,"depth":964,"text":1388},{"id":1418,"depth":959,"text":1419},{"id":1565,"depth":959,"text":1566},{"id":1636,"depth":959,"text":1637,"children":2194},[2195,2196,2197,2198,2199],{"id":1640,"depth":964,"text":1641},{"id":1650,"depth":964,"text":1651},{"id":1703,"depth":964,"text":1704},{"id":1727,"depth":964,"text":1348},{"id":1750,"depth":964,"text":1751},{"id":1781,"depth":959,"text":1782},{"id":1913,"depth":959,"text":1914},{"id":1972,"depth":959,"text":1973},{"id":800,"depth":959,"text":801,"children":2204},[2205,2206,2207,2208,2209,2210,2211],{"id":2029,"depth":964,"text":2030},{"id":2046,"depth":964,"text":2047},{"id":2053,"depth":964,"text":2054},{"id":2073,"depth":964,"text":2074},{"id":2085,"depth":964,"text":2086},{"id":2098,"depth":964,"text":2099},{"id":2118,"depth":964,"text":2119},{"id":915,"depth":959,"text":916},"2026-10-01T00:00:00.000Z","Create a manifest.json for a PWA or Chrome extension: required fields, minimal examples, install rules, and how to debug an invalid manifest.","\u002Fblog\u002Fcover\u002Fen\u002Fhow-to-create-manifest-json-cover.svg",[998],{},"\u002Fen\u002Fblog\u002Fhow-to-create-manifest-json",{"slug":2220,"text":2221,"btn":2222},"json-editor","Writing a manifest? Format and validate it before you ship:","Open JSON Editor",{"title":1016,"description":2214},"en\u002Fblog\u002Fhow-to-create-manifest-json",[1009,1028,2226,2227,1079],"PWA","Chrome Extension","dhcMuyNAGtdBybHlCRCMA-XP6HsZqgyITOEyM1yK9vE",{"id":2230,"title":2231,"author":7,"body":2232,"category":991,"date":3344,"description":3345,"draft":994,"extension":995,"h1":2237,"image":3346,"lastmod":3344,"locales":3347,"meta":3348,"navigation":1000,"path":3349,"promo":3350,"seo":3352,"stem":3353,"tags":3354,"__hash__":3358},"blog\u002Fen\u002Fblog\u002Fhow-to-create-json-file.md","How to Create a JSON File: Step-by-Step Guide",{"type":9,"value":2233,"toc":3310},[2234,2238,2245,2252,2255,2259,2262,2268,2274,2290,2293,2326,2341,2345,2351,2355,2360,2408,2423,2427,2432,2459,2464,2468,2474,2490,2494,2497,2537,2551,2555,2558,2564,2571,2577,2581,2584,2727,2745,2749,2884,2890,2894,2897,2903,2912,2918,2924,2941,2947,2951,2954,2975,2978,2982,2985,2989,2996,3014,3018,3024,3030,3034,3037,3043,3046,3048,3053,3056,3065,3071,3084,3103,3116,3119,3126,3128,3132,3151,3155,3158,3165,3176,3180,3186,3190,3209,3213,3222,3231,3246,3250,3258,3260,3304,3306],[12,2235,2237],{"id":2236},"how-to-create-a-json-file-step-by-step-guide-for-beginners","How to Create a JSON File: Step-by-Step Guide for Beginners",[28,2239,2240,2241,2244],{},"A JSON file is just a text file with the ",[25,2242,2243],{},".json"," extension. You do not need special software, a paid tool, or an account — Notepad, TextEdit, and VS Code can all create one.",[28,2246,2247,2248,2251],{},"What trips people up is rarely the writing. It is the saving: Windows silently appending ",[25,2249,2250],{},".txt",", macOS TextEdit saving rich text instead of plain text, and a missing comma that makes the file unreadable to every JSON parser.",[28,2253,2254],{},"This guide covers what a JSON file is, how to create one on each operating system, the syntax rules that decide whether your file is valid, how to validate it, and how to generate JSON files from code.",[71,2256,2258],{"id":2257},"what-is-a-json-file","What is a JSON file?",[28,2260,2261],{},"JSON (JavaScript Object Notation) is a plain-text data format built from two structures — objects and arrays — and six value types: string, number, boolean, null, object, and array.",[28,2263,2264,2265,2267],{},"A JSON file is a text file that contains JSON and uses the ",[25,2266,2243],{}," extension:",[17,2269,2272],{"className":2270,"code":2271,"language":1354,"meta":23},[1352],"{\n  \"name\": \"Ada Lovelace\",\n  \"role\": \"engineer\",\n  \"active\": true,\n  \"projects\": [\"analytical-engine\", \"bernoulli-numbers\"]\n}\n",[25,2273,2271],{"__ignoreMap":23},[28,2275,2276,2277,2282,2283,2286,2287,2289],{},"Per ",[57,2278,2281],{"href":2279,"rel":2280},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc8259",[81],"RFC 8259",", the registered media type is ",[25,2284,2285],{},"application\u002Fjson"," and the file extension is ",[25,2288,2243],{},". Because it is plain text, you can read and edit it anywhere — and any programming language can parse it.",[28,2291,2292],{},"JSON files are used for:",[135,2294,2295,2308,2314,2320],{},[138,2296,2297,735,2300,265,2303,265,2306,69],{},[32,2298,2299],{},"Configuration:",[25,2301,2302],{},"package.json",[25,2304,2305],{},"tsconfig.json",[25,2307,1028],{},[138,2309,2310,2313],{},[32,2311,2312],{},"Data exchange:"," API request and response bodies.",[138,2315,2316,2319],{},[32,2317,2318],{},"Saved data:"," exports, fixtures, and test datasets.",[138,2321,2322,2325],{},[32,2323,2324],{},"Logs:"," structured one-line records.",[28,2327,2328,2329,2332,2333,2336,2337,69],{},"A JSON file has one root value. It is either an object (",[25,2330,2331],{},"{ }",") or an array (",[25,2334,2335],{},"[ ]",") in practice, and everything else nests inside it. If you are new to the format itself, start with ",[57,2338,2340],{"href":2339},"\u002Fblog\u002Fwhat-is-json","What Is JSON? Structure, Syntax, and Common Mistakes",[71,2342,2344],{"id":2343},"how-to-create-a-json-file-with-a-text-editor","How to create a JSON file with a text editor",[28,2346,2347,2348,2350],{},"Every operating system follows the same three steps: write the JSON, save the file with a ",[25,2349,2243],{}," extension as UTF-8, then validate it. The default editors differ, and each has one trap.",[105,2352,2354],{"id":2353},"windows-notepad-or-vs-code","Windows: Notepad or VS Code",[28,2356,2357],{},[32,2358,2359],{},"Notepad:",[530,2361,2362,2365,2371,2387,2393],{},[138,2363,2364],{},"Open Notepad and paste or type your JSON.",[138,2366,2367,2368,69],{},"Choose ",[32,2369,2370],{},"File → Save As",[138,2372,1810,2373,2376,2377,2380,2381,2383,2384,69],{},[32,2374,2375],{},"Save as type"," to ",[32,2378,2379],{},"All Files (*.*)"," — this is the step people skip. If it stays on \"Text Documents (*.txt)\", Notepad appends ",[25,2382,2250],{}," and you get ",[25,2385,2386],{},"data.json.txt",[138,2388,2389,2390,69],{},"Enter the full file name including the extension: ",[25,2391,2392],{},"data.json",[138,2394,1810,2395,2376,2398,2401,2402,953,2405,69],{},[32,2396,2397],{},"Encoding",[32,2399,2400],{},"UTF-8",", then save. Recent versions of Notepad default to UTF-8, but check the dropdown — it is the difference between ",[25,2403,2404],{},"café",[25,2406,2407],{},"cafÃ©",[28,2409,2410,2413,2414,2416,2417,2419,2420,69],{},[32,2411,2412],{},"VS Code"," is easier: create a new file, select ",[32,2415,1009],{}," as the language mode, paste the content, and save as ",[25,2418,2392],{},". VS Code validates as you type and can format the document with ",[32,2421,2422],{},"Format Document",[105,2424,2426],{"id":2425},"macos-textedit-or-vs-code","macOS: TextEdit or VS Code",[28,2428,2429],{},[32,2430,2431],{},"TextEdit:",[530,2433,2434,2444,2447,2456],{},[138,2435,2436,2437,1740,2440,2443],{},"Open TextEdit and choose ",[32,2438,2439],{},"Format → Make Plain Text",[32,2441,2442],{},"Shift + Cmd + T",") before typing. TextEdit defaults to rich text, and saving rich text produces RTF, not JSON.",[138,2445,2446],{},"Paste or type your JSON.",[138,2448,2449,2450,2452,2453,2455],{},"In the save dialog, type the full name with the extension — ",[25,2451,2392],{}," — and make sure the option to append ",[25,2454,2250],{}," when no extension is given is not active.",[138,2457,2458],{},"Save.",[28,2460,2461,2463],{},[32,2462,2412],{}," avoids both problems and is the better default on macOS too.",[105,2465,2467],{"id":2466},"linux-nano-gedit-or-vs-code","Linux: nano, gedit, or VS Code",[17,2469,2472],{"className":2470,"code":2471,"language":1951,"meta":23},[1949],"nano data.json\n",[25,2473,2471],{"__ignoreMap":23},[28,2475,2476,2477,953,2480,2483,2484,2487,2488,69],{},"Type or paste the JSON, then press ",[32,2478,2479],{},"Ctrl + O",[32,2481,2482],{},"Enter"," to save, ",[32,2485,2486],{},"Ctrl + X"," to exit. Desktop editors such as gedit and VS Code work the same way — just make sure the file name ends in ",[25,2489,2243],{},[105,2491,2493],{"id":2492},"the-saving-checklist","The saving checklist",[28,2495,2496],{},"Whatever editor you use, confirm three things before you trust the file:",[162,2498,2499,2509],{},[165,2500,2501],{},[168,2502,2503,2506],{},[171,2504,2505],{},"Check",[171,2507,2508],{},"Why it matters",[181,2510,2511,2521,2529],{},[168,2512,2513,2518],{},[186,2514,2515,2516],{},"The name ends in ",[25,2517,2243],{},[186,2519,2520],{},"The extension tells editors, servers, and tools how to treat the file.",[168,2522,2523,2526],{},[186,2524,2525],{},"It is plain text, not rich text",[186,2527,2528],{},"Word, Google Docs, and TextEdit's rich-text mode add formatting that is not JSON.",[168,2530,2531,2534],{},[186,2532,2533],{},"The encoding is UTF-8",[186,2535,2536],{},"Non-UTF-8 files produce garbled characters; a UTF-8 BOM makes some parsers throw.",[28,2538,2539,2540,2542,2543,2546,2547,2550],{},"If your file might actually be ",[25,2541,2386],{},", check from a terminal (",[25,2544,2545],{},"dir"," on Windows, ",[25,2548,2549],{},"ls"," on macOS and Linux) rather than trusting File Explorer or Finder — both hide known extensions by default.",[71,2552,2554],{"id":2553},"step-by-step-create-your-first-json-file","Step-by-step: create your first JSON file",[28,2556,2557],{},"Here is a complete first file. It is an object with four keys and one nested array:",[17,2559,2562],{"className":2560,"code":2561,"language":1354,"meta":23},[1352],"{\n  \"project\": \"json-toolbox\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Ada\",\n  \"tags\": [\"json\", \"config\"]\n}\n",[25,2563,2561],{"__ignoreMap":23},[28,2565,2566,2567,2570],{},"Save it as ",[25,2568,2569],{},"project.json",". An array of objects is equally valid as the root value:",[17,2572,2575],{"className":2573,"code":2574,"language":1354,"meta":23},[1352],"[\n  { \"id\": 1, \"name\": \"Ada\", \"active\": true },\n  { \"id\": 2, \"name\": \"Lin\", \"active\": false }\n]\n",[25,2576,2574],{"__ignoreMap":23},[105,2578,2580],{"id":2579},"syntax-rules-that-decide-whether-the-file-works","Syntax rules that decide whether the file works",[28,2582,2583],{},"JSON is strict. These are the rules that cause most first-file failures:",[162,2585,2586,2599],{},[165,2587,2588],{},[168,2589,2590,2593,2596],{},[171,2591,2592],{},"Rule",[171,2594,2595],{},"Valid",[171,2597,2598],{},"Invalid",[181,2600,2601,2616,2631,2646,2660,2673,2694,2714],{},[168,2602,2603,2606,2611],{},[186,2604,2605],{},"Strings use double quotes",[186,2607,2608],{},[25,2609,2610],{},"\"name\"",[186,2612,2613],{},[25,2614,2615],{},"'name'",[168,2617,2618,2621,2626],{},[186,2619,2620],{},"Keys are quoted",[186,2622,2623],{},[25,2624,2625],{},"{ \"name\": \"Ada\" }",[186,2627,2628],{},[25,2629,2630],{},"{ name: \"Ada\" }",[168,2632,2633,2636,2641],{},[186,2634,2635],{},"No trailing comma",[186,2637,2638],{},[25,2639,2640],{},"{ \"a\": 1, \"b\": 2 }",[186,2642,2643],{},[25,2644,2645],{},"{ \"a\": 1, \"b\": 2, }",[168,2647,2648,2651,2655],{},[186,2649,2650],{},"Members separated by commas",[186,2652,2653],{},[25,2654,2640],{},[186,2656,2657],{},[25,2658,2659],{},"{ \"a\": 1 \"b\": 2 }",[168,2661,2662,2665,2668],{},[186,2663,2664],{},"No comments",[186,2666,2667],{},"—",[186,2669,2670],{},[25,2671,2672],{},"{ \"a\": 1 } \u002F\u002F note",[168,2674,2675,2678,2686],{},[186,2676,2677],{},"Numbers have no leading zeros or hex",[186,2679,2680,265,2683],{},[25,2681,2682],{},"42",[25,2684,2685],{},"3.14",[186,2687,2688,265,2691],{},[25,2689,2690],{},"042",[25,2692,2693],{},"0x1F",[168,2695,2696,2706,2710],{},[186,2697,2698,2699,265,2701,287,2703],{},"No ",[25,2700,313],{},[25,2702,686],{},[25,2704,2705],{},"Infinity",[186,2707,2708],{},[25,2709,337],{},[186,2711,2712],{},[25,2713,686],{},[168,2715,2716,2719,2724],{},[186,2717,2718],{},"Escape newlines inside strings",[186,2720,2721],{},[25,2722,2723],{},"\"line1\\nline2\"",[186,2725,2726],{},"a literal line break inside a string",[28,2728,2729,2730,1191,2733,953,2735,2737,2738,2740,2741,2744],{},"Two of these deserve a note. ",[32,2731,2732],{},"Comments are not part of JSON",[25,2734,2060],{},[25,2736,2063],{}," make the file invalid, and only tools that explicitly accept JSONC will read it; see ",[57,2739,1562],{"href":1561},". And ",[32,2742,2743],{},"trailing commas are invalid"," even though they are fine in JavaScript object literals, which is why copied-and-pasted config so often fails to parse.",[71,2746,2748],{"id":2747},"common-mistakes-and-how-to-fix-them","Common mistakes and how to fix them",[162,2750,2751,2761],{},[165,2752,2753],{},[168,2754,2755,2757,2759],{},[171,2756,1428],{},[171,2758,1431],{},[171,2760,1434],{},[181,2762,2763,2782,2793,2808,2821,2838,2857,2871],{},[168,2764,2765,2770,2773],{},[186,2766,2767,2768],{},"File is named ",[25,2769,2386],{},[186,2771,2772],{},"Save dialog type was \"Text Documents\", or the extension is hidden",[186,2774,2775,2776,2779,2780],{},"Re-save with ",[32,2777,2778],{},"Save as type: All Files"," and type ",[25,2781,2392],{},[168,2783,2784,2787,2790],{},[186,2785,2786],{},"Parser reports an error at line 1, column 1",[186,2788,2789],{},"UTF-8 BOM at the start of the file",[186,2791,2792],{},"Save as UTF-8 without BOM",[168,2794,2795,2802,2805],{},[186,2796,2797,2799,2800],{},[25,2798,2404],{}," becomes ",[25,2801,2407],{},[186,2803,2804],{},"File saved as ANSI \u002F non-UTF-8",[186,2806,2807],{},"Re-save with UTF-8 encoding",[168,2809,2810,2813,2816],{},[186,2811,2812],{},"Editor shows formatting or fonts",[186,2814,2815],{},"File was saved as rich text (RTF\u002FDOCX)",[186,2817,2818,2819],{},"Use a plain-text editor and save as ",[25,2820,2243],{},[168,2822,2823,2828,2835],{},[186,2824,2825],{},[25,2826,2827],{},"SyntaxError: Unexpected token }",[186,2829,2830,2831,223,2833],{},"Trailing comma before ",[25,2832,41],{},[25,2834,268],{},[186,2836,2837],{},"Remove the last comma in the object or array",[168,2839,2840,2845,2852],{},[186,2841,2842],{},[25,2843,2844],{},"SyntaxError: Unexpected token \u002F",[186,2846,1051,2847,223,2849,2851],{},[25,2848,2060],{},[25,2850,2063],{}," comment",[186,2853,2854,2855],{},"Remove comments, or convert with ",[57,2856,1900],{"href":1899},[168,2858,2859,2865,2868],{},[186,2860,2861,2864],{},[25,2862,2863],{},"Unexpected token '"," in JSON`",[186,2866,2867],{},"Single-quoted strings",[186,2869,2870],{},"Replace with double quotes",[168,2872,2873,2876,2879],{},[186,2874,2875],{},"Error mentions an unexpected string or colon",[186,2877,2878],{},"Unquoted key",[186,2880,2881,2882],{},"Quote the key: ",[25,2883,2625],{},[28,2885,2886,2887,2889],{},"When several of these are present at once, fixing them by hand is slow. Paste the file into ",[57,2888,60],{"href":59},", which fixes trailing commas, single quotes, unquoted keys, missing brackets, comments, and Python-style constants, then copy or download the valid result.",[71,2891,2893],{"id":2892},"how-to-validate-a-json-file","How to validate a JSON file",[28,2895,2896],{},"\"Valid\" has one meaning for a JSON file: a strict parser can read it without error. Four ways to check:",[28,2898,2899,2902],{},[32,2900,2901],{},"1. Editor feedback."," VS Code underlines syntax errors as you type and shows the message on hover. This catches most problems before you save.",[28,2904,2905,2908,2909,2911],{},[32,2906,2907],{},"2. In the browser."," Paste or open the file in the ",[57,2910,714],{"href":713},". It validates live, highlights syntax, and lets you format or minify the document before you copy or download it — no account and no upload, because it runs in your browser.",[28,2913,2914,2917],{},[32,2915,2916],{},"3. Command line."," Both of these parse the file and print it, so a parse error means the file is invalid:",[17,2919,2922],{"className":2920,"code":2921,"language":1951,"meta":23},[1949],"jq . data.json\npython -m json.tool data.json\n",[25,2923,2921],{"__ignoreMap":23},[28,2925,2926,2929,2930,2932,2933,2935,2936,2940],{},[32,2927,2928],{},"4. Schema validation."," Syntax is only the first layer. If the file has to match an expected structure — required fields, types, ranges — validate it against a JSON Schema. Generate a starting schema from a representative file with the ",[57,2931,1963],{"href":1962},", then check data against it with the ",[57,2934,1968],{"href":1967},". See ",[57,2937,2939],{"href":2938},"\u002Fblog\u002Fjson-validation-syntax-vs-schema","JSON Validation Explained"," for how the layers differ.",[28,2942,2943,2944,2946],{},"If a file fails to parse and you are not sure why, ",[57,2945,68],{"href":67}," walks through the error messages one by one.",[71,2948,2950],{"id":2949},"create-a-json-file-online","Create a JSON file online",[28,2952,2953],{},"If you would rather not deal with Save As dialogs, a browser-based editor does the same job and hands you a downloadable file:",[135,2955,2956,2966],{},[138,2957,2958,2962,2963,2965],{},[32,2959,2960],{},[57,2961,714],{"href":713}," — paste or open JSON, edit it in a syntax-highlighted editor with live validation, format or minify it, then copy or download the ",[25,2964,2243],{}," file. This is the closest equivalent to \"create a JSON file online\" and works on any OS, including Chromebooks and tablets.",[138,2967,2968,2974],{},[32,2969,2970],{},[57,2971,2973],{"href":2972},"\u002Ftools\u002Fconvert\u002Fjson-array-generator","JSON Array Generator"," — if you need a file full of sample records rather than one hand-written object, set the number of items and the field names and download a pretty-printed array. Useful for test fixtures and demos.",[28,2976,2977],{},"Both run entirely in your browser, so nothing you paste is sent to a server.",[71,2979,2981],{"id":2980},"generate-json-files-from-code","Generate JSON files from code",[28,2983,2984],{},"When data already lives in your program, do not hand-write the file — let the code write it.",[105,2986,2988],{"id":2987},"python","Python",[17,2990,2994],{"className":2991,"code":2993,"language":2987,"meta":23},[2992],"language-python","import json\n\ndata = {\n    \"project\": \"json-toolbox\",\n    \"version\": \"1.0.0\",\n    \"author\": \"Ada\",\n    \"tags\": [\"json\", \"config\"],\n}\n\nwith open(\"project.json\", \"w\", encoding=\"utf-8\") as f:\n    json.dump(data, f, indent=2, ensure_ascii=False)\n    f.write(\"\\n\")\n",[25,2995,2993],{"__ignoreMap":23},[28,2997,2998,3001,3002,3005,3006,3009,3010,3013],{},[25,2999,3000],{},"indent=2"," produces readable output; drop it for a compact file. ",[25,3003,3004],{},"ensure_ascii=False"," keeps non-ASCII characters readable instead of escaping them, which is why opening the file with ",[25,3007,3008],{},"encoding=\"utf-8\""," matters. Use ",[25,3011,3012],{},"json.dumps(data)"," when you want the JSON as a string rather than a file.",[105,3015,3017],{"id":3016},"nodejs","Node.js",[17,3019,3022],{"className":3020,"code":3021,"language":94,"meta":23},[92],"import { writeFile } from 'node:fs\u002Fpromises'\n\nconst data = {\n  project: 'json-toolbox',\n  version: '1.0.0',\n  author: 'Ada',\n  tags: ['json', 'config'],\n}\n\nawait writeFile('project.json', JSON.stringify(data, null, 2) + '\\n', 'utf8')\n",[25,3023,3021],{"__ignoreMap":23},[28,3025,3026,3029],{},[25,3027,3028],{},"JSON.stringify(value, null, 2)"," adds two-space indentation; omit the last two arguments for minified output.",[105,3031,3033],{"id":3032},"in-the-browser","In the browser",[28,3035,3036],{},"To let a user download a file your page generated:",[17,3038,3041],{"className":3039,"code":3040,"language":94,"meta":23},[92],"const text = JSON.stringify(data, null, 2)\nconst blob = new Blob([text], { type: 'application\u002Fjson' })\nconst url = URL.createObjectURL(blob)\n\nconst a = document.createElement('a')\na.href = url\na.download = 'project.json'\na.click()\n\nURL.revokeObjectURL(url)\n",[25,3042,3040],{"__ignoreMap":23},[28,3044,3045],{},"This never touches a server — the file is assembled in the page and downloaded from memory.",[71,3047,1048],{"id":1047},[28,3049,1051,3050,3052],{},[25,3051,1028],{}," is not a different format. It is an ordinary JSON file whose contents are defined by whichever platform reads it — so \"how do I create one\" really means \"what fields does this platform expect\".",[28,3054,3055],{},"Three common cases:",[28,3057,3058,3061,3062,69],{},[32,3059,3060],{},"Progressive Web App (web app manifest)"," — describes how your app appears when installed: name, icons, start URL, and display mode. Referenced from HTML with ",[25,3063,3064],{},"\u003Clink rel=\"manifest\" href=\"\u002Fmanifest.json\">",[17,3066,3069],{"className":3067,"code":3068,"language":1354,"meta":23},[1352],"{\n  \"name\": \"JSON Toolbox\",\n  \"short_name\": \"JSON Toolbox\",\n  \"start_url\": \"\u002F\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\",\n  \"theme_color\": \"#0284c7\",\n  \"icons\": [\n    {\n      \"src\": \"\u002Ficons\u002Ficon-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image\u002Fpng\"\n    },\n    {\n      \"src\": \"\u002Ficons\u002Ficon-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\u002Fpng\"\n    }\n  ]\n}\n",[25,3070,3068],{"__ignoreMap":23},[28,3072,3073,3074,638,3078,3083],{},"The specification is the ",[57,3075,3077],{"href":1148,"rel":3076},[81],"W3C Web Application Manifest",[57,3079,3082],{"href":3080,"rel":3081},"https:\u002F\u002Fweb.dev\u002Farticles\u002Fadd-manifest",[81],"web.dev"," has a practical walkthrough.",[28,3085,3086,3089,3090,3092,3093,3096,3097,3102],{},[32,3087,3088],{},"Chrome extension"," — every extension has a ",[25,3091,1028],{}," declaring its name, version, and permissions. The current version is ",[57,3094,1578],{"href":1590,"rel":3095},[81],"; see MDN's ",[57,3098,3100,1599],{"href":1595,"rel":3099},[81],[25,3101,1028],{}," for the key list.",[28,3104,3105,3108,3109,3111,3112,3115],{},[32,3106,3107],{},"Framework manifests"," — frameworks generate or consume their own. Next.js, for example, supports ",[25,3110,1987],{}," (or ",[25,3113,3114],{},"manifest.ts",") and serves the file for you.",[28,3117,3118],{},"The syntax rules in this guide apply to all of them: valid JSON first, correct fields second. Many editors accept comments in these files because they read them as JSONC — but the platform that consumes the file may not, so check before shipping comments.",[28,3120,3121,3122,69],{},"For step-by-step examples with the required fields for each spec — PWA web app manifests and Chrome extension Manifest V3 — see ",[57,3123,3125],{"href":3124},"\u002Fblog\u002Fhow-to-create-manifest-json","How to Create a manifest.json File",[71,3127,801],{"id":800},[105,3129,3131],{"id":3130},"can-i-create-a-json-file-in-notepad","Can I create a JSON file in Notepad?",[28,3133,3134,3135,3137,3138,2376,3140,3142,3143,3145,3146,3148,3149,69],{},"Yes. Write the JSON, choose ",[32,3136,2370],{},", set ",[32,3139,2375],{},[32,3141,2379],{},", type the name as ",[25,3144,2392],{},", and pick ",[32,3147,2400],{}," as the encoding. Skipping \"All Files\" is what produces ",[25,3150,2386],{},[105,3152,3154],{"id":3153},"do-i-need-special-software-to-create-a-json-file","Do I need special software to create a JSON file?",[28,3156,3157],{},"No. Any plain-text editor works — Notepad, TextEdit, nano, VS Code. A code editor adds syntax highlighting and live validation, which is why it is recommended, but it is not required.",[105,3159,3161,3162,3164],{"id":3160},"how-do-i-make-a-json-file-on-a-mac","How do I make a ",[25,3163,2243],{}," file on a Mac?",[28,3166,3167,3168,1740,3170,3172,3173,3175],{},"Use TextEdit with ",[32,3169,2439],{},[32,3171,2442],{},") first, then save with the full name ",[25,3174,2392],{},". Or use VS Code, which saves plain text with the extension you type and validates as you go.",[105,3177,3179],{"id":3178},"why-does-my-json-file-not-work-even-though-it-looks-correct","Why does my JSON file not work even though it looks correct?",[28,3181,3182,3183,3185],{},"Most often it is one of four things: the file is actually ",[25,3184,2386],{},", it was saved as rich text or with a BOM, it contains a trailing comma, or it has comments. Validate the file — an error message with a line and column points straight at the problem.",[105,3187,3189],{"id":3188},"can-a-json-file-have-comments","Can a JSON file have comments?",[28,3191,3192,3193,953,3195,3197,3198,3201,3202,3204,3205,3208],{},"No. Standard JSON has no comment syntax, so ",[25,3194,2060],{},[25,3196,2063],{}," make the file invalid. Use a ",[25,3199,3200],{},"_comment"," key, keep documentation outside the file, or work in JSONC and strip comments before shipping. Full details in ",[57,3203,1562],{"href":1561},", and the ",[57,3206,3207],{"href":1899},"JSONC to JSON Converter"," removes them for you.",[105,3210,3212],{"id":3211},"is-a-json-file-the-same-as-a-javascript-object","Is a JSON file the same as a JavaScript object?",[28,3214,3215,3216,3219,3220,69],{},"No. A JSON file is text; a JavaScript object literal is code. JavaScript allows unquoted keys, trailing commas, single quotes, and comments — none of which are valid JSON. That is why an object copied out of a ",[25,3217,3218],{},".js"," file often fails ",[25,3221,84],{},[105,3223,3225,3226,953,3228,3230],{"id":3224},"what-is-the-difference-between-json-and-webmanifest","What is the difference between ",[25,3227,2243],{},[25,3229,2036],{},"?",[28,3232,3233,3234,3236,3237,3239,3240,3242,3243,3245],{},"Both contain JSON; only the convention differs. ",[25,3235,2036],{}," is the file extension recommended by the W3C for a web app manifest, served as ",[25,3238,2040],{},", while ",[25,3241,2243],{}," is the general extension for any JSON document. Many projects still use ",[25,3244,1028],{}," with no issue.",[105,3247,3249],{"id":3248},"how-large-can-a-json-file-be","How large can a JSON file be?",[28,3251,3252,3253,3257],{},"JSON itself sets no size limit. Practical limits come from the tool reading the file: editor memory, parser configuration, and server upload caps. For testing how your own tools behave, the ",[57,3254,3256],{"href":3255},"\u002Fblog\u002Ffree-realistic-json-test-data","free realistic JSON test datasets"," range from small demos to large files.",[71,3259,916],{"id":915},[135,3261,3262,3274,3282,3290,3298],{},[138,3263,3264,3267,3268,3270,3271,3273],{},[32,3265,3266],{},"Ready to write one?"," Open the ",[57,3269,714],{"href":713}," — paste, validate, format, and download a ",[25,3272,2243],{}," file without installing anything.",[138,3275,3276,3279,3280,69],{},[32,3277,3278],{},"Need sample records?"," Generate an array with the ",[57,3281,2973],{"href":2972},[138,3283,3284,3287,3288,69],{},[32,3285,3286],{},"File already broken?"," Fix trailing commas, quotes, and comments with ",[57,3289,60],{"href":59},[138,3291,3292,940,3295,69],{},[32,3293,3294],{},"Wondering about comments?",[57,3296,3297],{"href":1561},"Comments in JSON: Why They're Not Allowed and What to Use Instead",[138,3299,3300,948,3302,69],{},[32,3301,2168],{},[57,3303,68],{"href":67},[2172,3305],{},[28,3307,3308],{},[113,3309,2178],{},{"title":23,"searchDepth":959,"depth":959,"links":3311},[3312,3313,3319,3322,3323,3324,3325,3330,3331,3343],{"id":2257,"depth":959,"text":2258},{"id":2343,"depth":959,"text":2344,"children":3314},[3315,3316,3317,3318],{"id":2353,"depth":964,"text":2354},{"id":2425,"depth":964,"text":2426},{"id":2466,"depth":964,"text":2467},{"id":2492,"depth":964,"text":2493},{"id":2553,"depth":959,"text":2554,"children":3320},[3321],{"id":2579,"depth":964,"text":2580},{"id":2747,"depth":959,"text":2748},{"id":2892,"depth":959,"text":2893},{"id":2949,"depth":959,"text":2950},{"id":2980,"depth":959,"text":2981,"children":3326},[3327,3328,3329],{"id":2987,"depth":964,"text":2988},{"id":3016,"depth":964,"text":3017},{"id":3032,"depth":964,"text":3033},{"id":1047,"depth":959,"text":1048},{"id":800,"depth":959,"text":801,"children":3332},[3333,3334,3335,3337,3338,3339,3340,3342],{"id":3130,"depth":964,"text":3131},{"id":3153,"depth":964,"text":3154},{"id":3160,"depth":964,"text":3336},"How do I make a .json file on a Mac?",{"id":3178,"depth":964,"text":3179},{"id":3188,"depth":964,"text":3189},{"id":3211,"depth":964,"text":3212},{"id":3224,"depth":964,"text":3341},"What is the difference between .json and .webmanifest?",{"id":3248,"depth":964,"text":3249},{"id":915,"depth":959,"text":916},"2026-09-30T00:00:00.000Z","Create a JSON file on Windows, macOS, or Linux: write valid JSON, avoid the .json.txt trap, validate the result, and generate files from code.","\u002Fblog\u002Fcover\u002Fen\u002Fhow-to-create-json-file-cover.svg",[998],{},"\u002Fen\u002Fblog\u002Fhow-to-create-json-file",{"slug":2220,"text":3351,"btn":2222},"Want to write, format, and validate JSON without installing anything?",{"title":2231,"description":3345},"en\u002Fblog\u002Fhow-to-create-json-file",[1009,3355,714,3356,3357],"Beginners","File Format","Tutorial","i2tDp54BDyFQSPRjbCkSB9YU3FA0Ko8wTFj8gRCufeE",1791273857924]