Return an error instead of raising on malformed JSON - #535
Merged
Conversation
`json:decode/1` raises rather than returning an error, and
`oidcc_http_util:extract_successful_response/1` called it unguarded in both
clauses. A provider serving a syntactically malformed document under a JSON
content type therefore took the calling process down instead of returning
`{error, _}`, so every caller had to wrap oidcc in a try/catch.
The 200/201 clause now returns `{error, {invalid_json, Reason}}`. The non-2xx
clause hands back the undecoded body, keeping the status code that is the real
failure, exactly as the unknown content type branch already did.
The catch is deliberately narrow. A body that is not a binary means the adapter
broke its contract rather than the provider serving something bad, so it still
crashes with the stack trace pointing at the adapter. Reporting it as a
malformed document would hide the caller's bug, and on the non-2xx path it would
also put a value outside `error()` into `{http_error, _, Body}`.
This covers syntax only. A document that parses but is not a JSON object, `null`
for instance, is a separate problem handled where the document is consumed.
ericmj
marked this pull request as ready for review
August 4, 2026 03:25
maennchen
approved these changes
Aug 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
json:decode/1raises rather than returning an error, andoidcc_http_util:extract_successful_response/1called it unguarded in both of itsclauses. A provider that serves a syntactically malformed document under a JSON content
type takes the calling process down instead of returning
{error, _}, so every callerhas to wrap oidcc in a try/catch to be safe.
To reproduce, point an adapter at
{ok, {{"HTTP/1.1", 200, ""}, [{"content-type", "application/json"}], <<"{\"issuer\": ">>}}and call
oidcc_provider_configuration:load_configuration/2. It dies witherror:unexpected_end.The 200/201 clause now returns
{error, {invalid_json, Reason}}, a new member ofoidcc_http_util:error(). Every module consuming that union includes it by referencerather than re-listing its members, so nothing downstream changes.
The non-2xx clause hands back the undecoded body instead. The status code is the real
failure there, and
{http_error, Status, Body}already permits a binary body, so aprovider that can't format its own error document no longer masks its own 500. That's
what the unknown content type branch already did.
The catch is narrow on purpose:
decode_json/1is guarded onis_binary(Body). Anon-binary body means the adapter broke its contract, most often by dropping the
body_formatoption on the way tohttpc:request/5, so it keeps crashing with thestack trace pointing at the adapter instead of being reported as a malformed document.
Reporting it as
invalid_jsonwould also put a value outsideerror()into{http_error, _, Body}on the non-2xx path.This covers syntax only. A document that parses but isn't a JSON object,
nullforinstance, is a separate problem handled where the document is consumed.
One behaviour change: a malformed body used to raise inside
telemetry:span/3and emitan
exceptionevent. It now emitsstopwitherrorin the metadata, like every othererror path.
test/oidcc_http_adapter_test.erlasserts that.