From 1259bbb354844825d810f68edf85c7b4f5a254b5 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Mon, 24 Feb 2025 12:37:39 +0100 Subject: [PATCH] Improve json decode error messages When printing errors include the position that the error occured at if included in the error. --- lib/stdlib/src/erl_stdlib_errors.erl | 16 +++++++++++++++- lib/stdlib/src/json.erl | 3 ++- lib/stdlib/test/json_SUITE.erl | 11 +++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/stdlib/src/erl_stdlib_errors.erl b/lib/stdlib/src/erl_stdlib_errors.erl index d841a020d830..8bcc999b1e7e 100644 --- a/lib/stdlib/src/erl_stdlib_errors.erl +++ b/lib/stdlib/src/erl_stdlib_errors.erl @@ -27,7 +27,7 @@ StackTrace :: erlang:stacktrace(), ErrorMap :: #{pos_integer() => unicode:chardata()}. -format_error(_Reason, [{M,F,As,Info}|_]) -> +format_error(Reason, [{M,F,As,Info}|_]) -> ErrorInfoMap = proplists:get_value(error_info, Info, #{}), Cause = maps:get(cause, ErrorInfoMap, none), Res = case M of @@ -47,6 +47,8 @@ format_error(_Reason, [{M,F,As,Info}|_]) -> format_unicode_error(F, As); io -> format_io_error(F, As, Cause); + json -> + format_json_error(F, As, Reason, Cause); _ -> [] end, @@ -633,6 +635,18 @@ check_io_arguments([Type|TypeT], [Arg|ArgT], No) -> check_io_arguments(TypeT, ArgT, No+1)] end. +format_json_error(_F, _As, {invalid_byte, Int}, #{position := Position}) -> + Str = if 32 =< Int, Int < 127 -> + io_lib:format("invalid byte 16#~2.16.0B '~c' at byte position ~w", + [Int, Int, Position]); + true -> + io_lib:format("invalid byte 16#~2.16.0B at byte position ~w", + [Int, Position]) + end, + [{general, Str}]; +format_json_error(_, _, _, _) -> + [""]. + format_ets_error(delete_object, Args, Cause) -> format_object(Args, Cause); format_ets_error(give_away, [_Tab,Pid,_Gift]=Args, Cause) -> diff --git a/lib/stdlib/src/json.erl b/lib/stdlib/src/json.erl index bfa333eda303..19bf772e2aeb 100644 --- a/lib/stdlib/src/json.erl +++ b/lib/stdlib/src/json.erl @@ -541,7 +541,8 @@ invalid_byte(Bin, Skip) -> error({invalid_byte, Byte}, none, error_info(Skip)). error_info(Skip) -> - [{error_info, #{cause => #{position => Skip}}}]. + [{error_info, #{cause => #{position => Skip}, + module => erl_stdlib_errors}}]. %% %% Format implementation diff --git a/lib/stdlib/test/json_SUITE.erl b/lib/stdlib/test/json_SUITE.erl index 70f92848fe19..01e98e9018e4 100644 --- a/lib/stdlib/test/json_SUITE.erl +++ b/lib/stdlib/test/json_SUITE.erl @@ -56,7 +56,8 @@ property_integer_roundtrip/1, property_float_roundtrip/1, property_object_roundtrip/1, - property_escape_all/1 + property_escape_all/1, + error_info/1 ]). @@ -75,7 +76,8 @@ all() -> {group, format}, test_json_test_suite, {group, properties}, - counterexamples + counterexamples, + error_info ]. groups() -> @@ -1042,6 +1044,11 @@ test_file(yes, File, Data) -> test_file(no, File, Data) -> ?assertError(_, decode(Data), File). +error_info(_) -> + L = [{decode, [~'["valid string", not_valid'], [allow_rename, unexplained]}], + error_info_lib:test_error_info(json, L, [allow_nyi]). + + %% %% Property tests %%