hybriel
JSON.parse cannot fail softly
opened by architect · assigned to Caramboleyo
opened · updated
Found in mission 002. A webex function route doing JSON.parse(req.body) on {bad answers 500 with a body containing the located message (api.hl:31:9 ...), leaking the source path; log shows error.InvalidOperation in the event handler fiber. Server survives. Expected: a non-aborting parse (e.g. JSON.tryParse returning null or {error}) so apps can answer 400.
History
architect opened the ticket Anton commented Needs the creator's ruling: should JSON.parse get a form that does not abort (e.g. answers null) so an app can answer 400? Ran
JSON.parse('{bad'): a located abort. SPEC (the hlError row) says there is no catch, and that inside a request handler the abort becomes a 500 carrying the located message. So both the 500 and the source path in its body are specified today.Anton changed the state review Caramboleyo changed the state open Wouldn't our design here be to call on Error right after or is the problem here that if in a http request handler it never gets to that line then?
Architect commented Yes, that's the problem (answer from the reporter): in an HTTP function route, JSON.parse on a bad body aborts the handler at that line, so the route never gets to answer the client itself — it cannot say "400: the body is not valid JSON, field X". An
on Errorcan log or clean up, but the request is already lost (500 / no answer), and hybriel#30 showed it does not even catch every plugin error. That is why tickets and ident carry their own jsoncheck.hl that validates the text before calling JSON.parse. What an app needs: a way to get "not valid JSON" back as a value in the same handler (e.g. a result it can test) and answer with 400. Anton can say whetheron Errorcould hand the handler a way to still answer.Anton changed the state review on Errorcannot fix this. It runs after the located abort, and by then the handler that should answer the request is gone. It could only log, or let the framework send a 500.Proposal, keeping one error mechanism (the located abort, no try):
JSON.parsestays as it is and aborts on bad input.- A new
JSON.check(text)answers null for valid JSON, or a record{ message, line, col }for invalid JSON. - A route then does
let bad = JSON.check(req.body), and if bad is set answers 400 with bad.message; otherwise it parses. This replaces the jsoncheck.hl copies in tickets and ident. - The same shape could later serve other parsers (dates, numbers from text).
Separately, hl:web could answer a function route that aborts with a 500 carrying the located error in development, instead of dropping the request.
Yes, or another shape?
Reading is open to everyone. To comment or change the state, log in with ident (top right) and choose a display name.