In short
HttpService:JSONDecode(text) turns JSON text into a Luau table, and the text you gave it is not valid JSON. The three usual reasons: you passed it a URL (it does not download anything), the web request failed and you decoded its HTML error page, or the text is written like a Luau table instead of JSON. Fetch first with RequestAsync, check Success before you decode, and wrap JSONDecode in pcall so bad text gives a warning instead of stopping the script.
What the message means
ServerScriptService.Weather:8: Can't parse JSON
JSON has strict rules: keys in double quotes, : between a key and its value, no trailing commas, and true, false and null spelled exactly so. Any text that breaks them, including an empty string, cannot be decoded.
JSONDecode and JSONEncode work on text you already have and do not send requests, so they work even with HTTP requests turned off. Only GetAsync, PostAsync and RequestAsync fetch anything, and those need Allow HTTP Requests switched on.
Causes and fixes
Three things cause this error in practice. Each one below has the smallest code that triggers it, then the fix.
- A URL is passed to JSONDecode
- The request failed and its error page was decoded
- The text is written like a Luau table
A URL is passed to JSONDecode
It is easy to assume JSONDecode loads the address you give it. It does not: it tries to read the address itself as JSON, and a URL is not JSON.
local HttpService = game:GetService("HttpService")
-- JSONDecode does not download: Can't parse JSON
local data = HttpService:JSONDecode("https://example.com/weather.json")
print(data)
Download the text first with GetAsync or RequestAsync in a server Script, then decode what came back.
local HttpService = game:GetService("HttpService")
local ok, data = pcall(function()
local body = HttpService:GetAsync("https://example.com/weather.json")
return HttpService:JSONDecode(body)
end)
if ok then
print("weather:", data)
else
warn("[Weather] failed:", data)
end
The request failed and its error page was decoded
When a website is down, blocks the request or the address is wrong, RequestAsync still returns a body, often an HTML page that starts with <. Decoding that body without checking the result fails here instead of at the real problem.
local HttpService = game:GetService("HttpService")
local response = HttpService:RequestAsync({
Url = "https://example.com/api/leaderboard",
Method = "GET",
})
-- a 404 or 500 page is HTML: Can't parse JSON
local rows = HttpService:JSONDecode(response.Body)
print(rows)
Check Success (true for status codes 200 to 299) before decoding, and log the status and the start of the body when it fails, so you see the real error.
local HttpService = game:GetService("HttpService")
local function getJson(url: string): any?
local ok, response = pcall(function()
return HttpService:RequestAsync({ Url = url, Method = "GET" })
end)
if not ok then
warn("[HTTP] request error:", response)
return nil
end
local body = response.Body or ""
if not response.Success then
warn(`[HTTP] {response.StatusCode} {response.StatusMessage}: {string.sub(body, 1, 120)}`)
return nil
end
local decoded, result = pcall(HttpService.JSONDecode, HttpService, body)
if not decoded then
warn("[HTTP] not JSON:", string.sub(body, 1, 120))
return nil
end
return result
end
print(getJson("https://example.com/api/leaderboard"))
The text is written like a Luau table
Hand-written settings in a StringValue or an attribute often use Luau table syntax: {coins = 10}, single quotes or a trailing comma. JSON allows none of those.
local HttpService = game:GetService("HttpService")
local text = "{coins = 10, items = {'Sword', 'Shield',}}"
-- Luau syntax, not JSON: Can't parse JSON
local settings = HttpService:JSONDecode(text)
print(settings)
Write real JSON, with double-quoted keys and no trailing commas. The safest way to make JSON is to let Roblox write it: build a Luau table and call JSONEncode, then store that text.
local HttpService = game:GetService("HttpService")
local text = HttpService:JSONEncode({ coins = 10, items = { "Sword", "Shield" } })
print(text) --> {"coins":10,"items":["Sword","Shield"]}
local ok, settings = pcall(HttpService.JSONDecode, HttpService, text)
if ok then
print(settings.coins)
end
Fix it in your place
Paste the error, RoCode fixes it in your place
Copy the line from Output and paste it here. RoCode opens the script it names in the place you have open in Studio, works out which of the causes above it is, and edits the code there instead of handing you a snippet to paste.
RoCode is an AI agent for Roblox Studio: it reads the scripts in the place you have open, finds the line and edits it there, and every change is an undo point. It runs on Windows or macOS with a desktop browser. Free to start, with free credits every day.
How to find the line that causes it
- Open Output (Window menu, or the Script tab), clear it with Ctrl+K (⌘K on Mac), and press Play.
- Find the first red line. It starts with the script's place in the Explorer and the line number, such as
ServerScriptService.Shop:12:. - Click the red line. Studio opens that script with the cursor on the failing line.
- Read the lines between
Stack BeginandStack Endunder it: they list the calls that led there, newest first, so you can see which function called the broken one. - Still not sure which value is wrong? Add
print(typeof(x), x)just above the line, or set a breakpoint on it and read the values in the Watch window.
Questions
Does JSONDecode need HTTP requests enabled?
No. It only reads text you already have. Fetching the text with GetAsync or RequestAsync needs Allow HTTP Requests on, in a server Script.
Can I call roblox.com APIs from my game?
Not with HttpService: requests to Roblox's own web addresses are refused with HttpService is not allowed to access ROBLOX resources. Use the matching engine API in your script instead, or a Roblox Open Cloud endpoint where one exists.
How do I see what text failed to decode?
Print the first part of it just before you decode: print(string.sub(text, 1, 200)). If it starts with <, it is HTML; if it is empty, the request returned nothing.
Can RoCode fix it?
Yes. Paste the Output line into RoCode. It reads the script in the place you have open, adds the request, the Success check and the pcall, and fixes the text if it is not valid JSON.
Sources and further reading
- Roblox Creator Docs: HttpService. JSONDecode, JSONEncode, GetAsync and RequestAsync
- Roblox Creator Docs: HTTP service
How the code was checked: every block marked Fixed passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 4 November 2026), and every block marked Breaks compiles and fails only when it runs. The message wording was checked against the message strings in Roblox Studio itself (macOS build installed on 24 October 2026) on 4 November 2026. A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.