Why doesn't `RAISE EXCEPTION` provide error context?

Started by Taytayabout 11 years ago9 messagesgeneral
Jump to latest
#1Taytay
taylor@youneedabudget.com

We make heavy use of `GET STACKED DIAGNOSTICS` to determine where errors
happened.
However, I am trying to use RAISE EXCEPTION to report errors, and have
discovered that RAISE is specifically prevented from adding to the error
context:

So that means that this doesn't work:

I've posted more details here:
http://dba.stackexchange.com/questions/96743/postgres-how-to-get-stack-trace-for-a-manually-raised-exception

That context would be awfully useful for us, even for manually generated
exceptions.
Can anyone shed some light on A) why this is, and B) if it's still desired,
and C) if so, are there any workarounds? Is there an exception I can trick
Postgres into throwing that will include my user-generated string?

Many thanks for any help you can offer.

--
View this message in context: http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general

#2David G. Johnston
david.g.johnston@gmail.com
In reply to: Taytay (#1)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

Adding "raw" content present on Nabble that gets filtered by the mailing
list.

On Wednesday, April 1, 2015, Taytay <taylor@youneedabudget.com> wrote:

We make heavy use of `GET STACKED DIAGNOSTICS` to determine where errors
happened.
However, I am trying to use RAISE EXCEPTION to report errors, and have
discovered that RAISE is specifically prevented from adding to the error
context:

----
static void
plpgsql_exec_error_callback(void *arg)
{
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;
----

So that means that this doesn't work:

RAISE EXCEPTION 'This exception will not get a stack trace';

EXCEPTION WHEN others THEN

-- If the exception we're catching is one that Postgres threw,
-- like a divide by zero error, then this will get the full
-- stack trace of the place where the exception was thrown.
-- However, since we are catching an exception we raised manually
-- using RAISE EXCEPTION, there is no context/stack trace!
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;

Show quoted text

I've posted more details here:

http://dba.stackexchange.com/questions/96743/postgres-how-to-get-stack-trace-for-a-manually-raised-exception

That context would be awfully useful for us, even for manually generated
exceptions.
Can anyone shed some light on A) why this is, and B) if it's still desired,
and C) if so, are there any workarounds? Is there an exception I can trick
Postgres into throwing that will include my user-generated string?

Many thanks for any help you can offer.

#3Pavel Stehule
pavel.stehule@gmail.com
In reply to: David G. Johnston (#2)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

2015-04-02 9:13 GMT+02:00 David G. Johnston <david.g.johnston@gmail.com>:

Adding "raw" content present on Nabble that gets filtered by the mailing
list.

On Wednesday, April 1, 2015, Taytay <taylor@youneedabudget.com> wrote:

We make heavy use of `GET STACKED DIAGNOSTICS` to determine where errors
happened.
However, I am trying to use RAISE EXCEPTION to report errors, and have
discovered that RAISE is specifically prevented from adding to the error
context:

----
static void
plpgsql_exec_error_callback(void *arg)
{
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;
----

We talked more time about a change of this behave - the discus finished
without end

/messages/by-id/CAFj8pRDFHqv7cKXP-K+uBzW6627HytT7bct4ZxDBseLXc1Rcgg@mail.gmail.com

I am thinking, so current design is too simple and should be changed, and
if will be a agreement I can add this patch to next commitfest.

Regards

Pavel

Show quoted text

So that means that this doesn't work:

RAISE EXCEPTION 'This exception will not get a stack trace';

EXCEPTION WHEN others THEN

-- If the exception we're catching is one that Postgres threw,
-- like a divide by zero error, then this will get the full
-- stack trace of the place where the exception was thrown.
-- However, since we are catching an exception we raised manually
-- using RAISE EXCEPTION, there is no context/stack trace!
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;

I've posted more details here:

http://dba.stackexchange.com/questions/96743/postgres-how-to-get-stack-trace-for-a-manually-raised-exception

That context would be awfully useful for us, even for manually generated
exceptions.
Can anyone shed some light on A) why this is, and B) if it's still
desired,
and C) if so, are there any workarounds? Is there an exception I can trick
Postgres into throwing that will include my user-generated string?

Many thanks for any help you can offer.

#4David G. Johnston
david.g.johnston@gmail.com
In reply to: Pavel Stehule (#3)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

On Thursday, April 2, 2015, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2015-04-02 9:13 GMT+02:00 David G. Johnston <david.g.johnston@gmail.com
<javascript:_e(%7B%7D,'cvml','david.g.johnston@gmail.com');>>:

Adding "raw" content present on Nabble that gets filtered by the mailing
list.

On Wednesday, April 1, 2015, Taytay <taylor@youneedabudget.com
<javascript:_e(%7B%7D,'cvml','taylor@youneedabudget.com');>> wrote:

We make heavy use of `GET STACKED DIAGNOSTICS` to determine where errors
happened.
However, I am trying to use RAISE EXCEPTION to report errors, and have
discovered that RAISE is specifically prevented from adding to the error
context:

----
static void
plpgsql_exec_error_callback(void *arg)
{
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;
----

We talked more time about a change of this behave - the discus finished
without end

/messages/by-id/CAFj8pRDFHqv7cKXP-K+uBzW6627HytT7bct4ZxDBseLXc1Rcgg@mail.gmail.com

I am thinking, so current design is too simple and should be changed, and
if will be a agreement I can add this patch to next commitfest.

Regards

Pavel

So that means that this doesn't work:

RAISE EXCEPTION 'This exception will not get a stack trace';

EXCEPTION WHEN others THEN

-- If the exception we're catching is one that Postgres threw,
-- like a divide by zero error, then this will get the full
-- stack trace of the place where the exception was thrown.
-- However, since we are catching an exception we raised manually
-- using RAISE EXCEPTION, there is no context/stack trace!
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;

I've posted more details here:

http://dba.stackexchange.com/questions/96743/postgres-how-to-get-stack-trace-for-a-manually-raised-exception

That context would be awfully useful for us, even for manually generated
exceptions.
Can anyone shed some light on A) why this is, and B) if it's still
desired,
and C) if so, are there any workarounds? Is there an exception I can
trick
Postgres into throwing that will include my user-generated string?

Many thanks for any help you can offer.

The OP on this thread has introduced a potential compromise. Keep the
current printing behavior for RAISE but the construction of the error
itself should contain all of the relevant detail so that the caller can get
to the suppressed information via, in this instance, GET STACKED
DIAGNOSTICS inside an exception handler - a situation where the error is in
context but has not yet been printed.

Giving the function author the ability, via a new using clause, to bypass
the printing short-circuit is another feature to consider.

I haven't fully comprehended the design decisions and trade-offs but
omitting data to facilitate printing doesn't sound like an appropriate
solution - not that I have any clue how hard it would be separate the two
aspects. Likewise with adding in a short-circuit that is judgemental
without providing some means to bypass it. We are not talking about data
integrity or performance here and while I'll admit reducing verbosity is a
valid goal mis-use of a provided work-around mechanic is not that serious a
transgression and one readily noticed and somewhat readily corrected.

David J.

#5Pavel Stehule
pavel.stehule@gmail.com
In reply to: David G. Johnston (#4)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

The OP on this thread has introduced a potential compromise. Keep the

current printing behavior for RAISE but the construction of the error
itself should contain all of the relevant detail so that the caller can get
to the suppressed information via, in this instance, GET STACKED
DIAGNOSTICS inside an exception handler - a situation where the error is in
context but has not yet been printed.

Giving the function author the ability, via a new using clause, to bypass
the printing short-circuit is another feature to consider.

I haven't fully comprehended the design decisions and trade-offs but
omitting data to facilitate printing doesn't sound like an appropriate
solution - not that I have any clue how hard it would be separate the two
aspects. Likewise with adding in a short-circuit that is judgemental
without providing some means to bypass it. We are not talking about data
integrity or performance here and while I'll admit reducing verbosity is a
valid goal mis-use of a provided work-around mechanic is not that serious a
transgression and one readily noticed and somewhat readily corrected.

There is more aspects - current behave is too simply fix - but it works
almost time. We can enhance a RAISE statement, but default behave should be
practical. Usually we don't need stack for NOTICE level (and maybe for
WARNING level) and usually we would to have stack for EXCEPTION level. Now,
there is workaround due GET DIAGNOSTICS STACK, but it is workaround - and
the enhancing of GET DIAGNOSTICS was not designed for this purpose. Sure,
there are more variant of fixing - and we can implement more than one.

Regards

Pavel

Show quoted text

David J.

#6Taytay
taylor@youneedabudget.com
In reply to: Pavel Stehule (#5)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

There appears to be a fair amount of nuance here, but I am _very_ impressed
with how quickly you have responded. Thank you for your quick attention to
this issue! (Yet another thing that makes me happy to be using Postgres).

We have fair amount of business logic in Postgres functions, and the
ability to throw and catch exceptions, and pinpoint their source location
in our logs, will be _very_ helpful for us. I look forward to it.

This is perhaps a separate discussion, but as I await this patch, I'm
looking for a way to "trick" Postgres into throwing an exception that will
include a string of my choosing. Something like "SELECT 'This is an
exception' / 0 "
That would give me a "real" exception that is not subject to this
filtering, and if the error message was "Divide by zero: 'This is an
exception cannot' / 0"
I'm totally making that up of course, but you see what I'm getting at. Does
someone with better Postgres/SQL knowledge know of such an exception?

Thanks again,

Taylor

On Thu, Apr 2, 2015 at 2:07 AM, Pavel Stehule [via PostgreSQL] <
ml-node+s1045698n5844393h53@n5.nabble.com> wrote:

The OP on this thread has introduced a potential compromise. Keep the

current printing behavior for RAISE but the construction of the error
itself should contain all of the relevant detail so that the caller can get
to the suppressed information via, in this instance, GET STACKED
DIAGNOSTICS inside an exception handler - a situation where the error is in
context but has not yet been printed.

Giving the function author the ability, via a new using clause, to bypass
the printing short-circuit is another feature to consider.

I haven't fully comprehended the design decisions and trade-offs but
omitting data to facilitate printing doesn't sound like an appropriate
solution - not that I have any clue how hard it would be separate the two
aspects. Likewise with adding in a short-circuit that is judgemental
without providing some means to bypass it. We are not talking about data
integrity or performance here and while I'll admit reducing verbosity is a
valid goal mis-use of a provided work-around mechanic is not that serious a
transgression and one readily noticed and somewhat readily corrected.

There is more aspects - current behave is too simply fix - but it works
almost time. We can enhance a RAISE statement, but default behave should be
practical. Usually we don't need stack for NOTICE level (and maybe for
WARNING level) and usually we would to have stack for EXCEPTION level. Now,
there is workaround due GET DIAGNOSTICS STACK, but it is workaround - and
the enhancing of GET DIAGNOSTICS was not designed for this purpose. Sure,
there are more variant of fixing - and we can implement more than one.

Regards

Pavel

David J.

------------------------------
If you reply to this email, your message will be added to the discussion
below:

http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382p5844393.html
To unsubscribe from Why doesn't `RAISE EXCEPTION` provide error context?, click
here
<http://postgresql.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&amp;node=5844382&amp;code=dGF5bG9yQHlvdW5lZWRhYnVkZ2V0LmNvbXw1ODQ0MzgyfC03ODA0MjA3NDE=&gt;
.
NAML
<http://postgresql.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&amp;id=instant_html%21nabble%3Aemail.naml&amp;base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&amp;breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml&gt;

--
View this message in context: http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382p5844473.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

#7Melvin Davidson
melvin6925@gmail.com
In reply to: Taytay (#6)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

I believe the availability of trapping the error codes and raising the
appropriate message
is already in PLPGSQL. Please see the two sections below.

http://www.postgresql.org/docs/9.4/interactive/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING

http://www.postgresql.org/docs/9.4/interactive/errcodes-appendix.html

On Thu, Apr 2, 2015 at 12:01 PM, Taytay <taylor@youneedabudget.com> wrote:

There appears to be a fair amount of nuance here, but I am _very_
impressed with how quickly you have responded. Thank you for your quick
attention to this issue! (Yet another thing that makes me happy to be using
Postgres).

We have fair amount of business logic in Postgres functions, and the
ability to throw and catch exceptions, and pinpoint their source location
in our logs, will be _very_ helpful for us. I look forward to it.

This is perhaps a separate discussion, but as I await this patch, I'm
looking for a way to "trick" Postgres into throwing an exception that will
include a string of my choosing. Something like "SELECT 'This is an
exception' / 0 "
That would give me a "real" exception that is not subject to this
filtering, and if the error message was "Divide by zero: 'This is an
exception cannot' / 0"
I'm totally making that up of course, but you see what I'm getting at.
Does someone with better Postgres/SQL knowledge know of such an exception?

Thanks again,

Taylor

On Thu, Apr 2, 2015 at 2:07 AM, Pavel Stehule [via PostgreSQL] <[hidden
email] <http:///user/SendEmail.jtp?type=node&amp;node=5844473&amp;i=0&gt;&gt; wrote:

The OP on this thread has introduced a potential compromise. Keep the

current printing behavior for RAISE but the construction of the error
itself should contain all of the relevant detail so that the caller can get
to the suppressed information via, in this instance, GET STACKED
DIAGNOSTICS inside an exception handler - a situation where the error is in
context but has not yet been printed.

Giving the function author the ability, via a new using clause, to
bypass the printing short-circuit is another feature to consider.

I haven't fully comprehended the design decisions and trade-offs but
omitting data to facilitate printing doesn't sound like an appropriate
solution - not that I have any clue how hard it would be separate the two
aspects. Likewise with adding in a short-circuit that is judgemental
without providing some means to bypass it. We are not talking about data
integrity or performance here and while I'll admit reducing verbosity is a
valid goal mis-use of a provided work-around mechanic is not that serious a
transgression and one readily noticed and somewhat readily corrected.

There is more aspects - current behave is too simply fix - but it works
almost time. We can enhance a RAISE statement, but default behave should be
practical. Usually we don't need stack for NOTICE level (and maybe for
WARNING level) and usually we would to have stack for EXCEPTION level. Now,
there is workaround due GET DIAGNOSTICS STACK, but it is workaround - and
the enhancing of GET DIAGNOSTICS was not designed for this purpose. Sure,
there are more variant of fixing - and we can implement more than one.

Regards

Pavel

David J.

------------------------------
If you reply to this email, your message will be added to the
discussion below:

http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382p5844393.html
To unsubscribe from Why doesn't `RAISE EXCEPTION` provide error
context?, click here.
NAML
<http://postgresql.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&amp;id=instant_html%21nabble%3Aemail.naml&amp;base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&amp;breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml&gt;

------------------------------
View this message in context: Re: Why doesn't `RAISE EXCEPTION` provide
error context?
<http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382p5844473.html&gt;
Sent from the PostgreSQL - general mailing list archive
<http://postgresql.nabble.com/PostgreSQL-general-f1843780.html&gt; at
Nabble.com.

--
*Melvin Davidson*
I reserve the right to fantasize. Whether or not you
wish to share my fantasy is entirely up to you.

#8Taytay
taylor@youneedabudget.com
In reply to: Melvin Davidson (#7)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

Indeed it is possible Melvin. I read through those links, and I am afraid I
wasn't clear enough.

If Postgres throws an exception, we can handle it and get the context,
which will allow us to pinpoint exactly where the problem was, and what
functions were called leading up to the error. However, we are trying to
add our own manually RAISED exceptions for particular circumstances. And in
that case, I can "catch" the exception, but there is no context associated
with it. I'm looking for a workaround to tide me over until this is fixed.

Example: We have some functions that take a JSON parameter, extract some
values, and will eventually insert those values into the database. If a
property isn't set on the JSON that gets passed into that function, that
parameter is null, and we'll eventually see an error because the INSERT
into the database violates a NOT NULL constraint. Since Postgres threw that
error, I can handle that exception and return the context, showing me where
to look. Through debugging, _eventually_ figure out that the developer
might not have passed in the appropriate JSON data into the function (vs
many other reasons we could have seen a NOT NULL constraint error). So, I
would rather put a check like this at the top of my function:

--
important_variable = (p_request::json->>'important_variable')::integer;
IF (important_variable is NULL) THEN RAISE EXCEPTION 'important_variable
must not be NULL.'; END IF;
--

But I won't be able to get the context for that exception, and all I'll be
able to return from the function or write to the logs is
'important_variable must not be NULL.'. If that's the only place I throw
that error, I'll know where to look. Otherwise, I have no context, and
won't be able to determine where my exception was thrown. So I'm actually
better off _not_ throwing my own custom exceptions, even though I would
prefer to be more defensive about this sort of thing in my code.

I thought I might be able to "trick" postgres into throwing another
unrelated exception that would not only include my custom error message,
but allow me to extract the context, telling me the function where I should
begin debugging.

Many thanks,

Taylor

On Thu, Apr 2, 2015 at 10:45 AM, Melvin Davidson <melvin6925@gmail.com>
wrote:

Show quoted text

I believe the availability of trapping the error codes and raising the
appropriate message
is already in PLPGSQL. Please see the two sections below.

http://www.postgresql.org/docs/9.4/interactive/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING

http://www.postgresql.org/docs/9.4/interactive/errcodes-appendix.html

On Thu, Apr 2, 2015 at 12:01 PM, Taytay <taylor@youneedabudget.com> wrote:

There appears to be a fair amount of nuance here, but I am _very_
impressed with how quickly you have responded. Thank you for your quick
attention to this issue! (Yet another thing that makes me happy to be using
Postgres).

We have fair amount of business logic in Postgres functions, and the
ability to throw and catch exceptions, and pinpoint their source location
in our logs, will be _very_ helpful for us. I look forward to it.

This is perhaps a separate discussion, but as I await this patch, I'm
looking for a way to "trick" Postgres into throwing an exception that will
include a string of my choosing. Something like "SELECT 'This is an
exception' / 0 "
That would give me a "real" exception that is not subject to this
filtering, and if the error message was "Divide by zero: 'This is an
exception cannot' / 0"
I'm totally making that up of course, but you see what I'm getting at.
Does someone with better Postgres/SQL knowledge know of such an exception?

Thanks again,

Taylor

On Thu, Apr 2, 2015 at 2:07 AM, Pavel Stehule [via PostgreSQL] <[hidden
email] <http:///user/SendEmail.jtp?type=node&amp;node=5844473&amp;i=0&gt;&gt; wrote:

The OP on this thread has introduced a potential compromise. Keep the

current printing behavior for RAISE but the construction of the error
itself should contain all of the relevant detail so that the caller can get
to the suppressed information via, in this instance, GET STACKED
DIAGNOSTICS inside an exception handler - a situation where the error is in
context but has not yet been printed.

Giving the function author the ability, via a new using clause, to
bypass the printing short-circuit is another feature to consider.

I haven't fully comprehended the design decisions and trade-offs but
omitting data to facilitate printing doesn't sound like an appropriate
solution - not that I have any clue how hard it would be separate the two
aspects. Likewise with adding in a short-circuit that is judgemental
without providing some means to bypass it. We are not talking about data
integrity or performance here and while I'll admit reducing verbosity is a
valid goal mis-use of a provided work-around mechanic is not that serious a
transgression and one readily noticed and somewhat readily corrected.

There is more aspects - current behave is too simply fix - but it works
almost time. We can enhance a RAISE statement, but default behave should be
practical. Usually we don't need stack for NOTICE level (and maybe for
WARNING level) and usually we would to have stack for EXCEPTION level. Now,
there is workaround due GET DIAGNOSTICS STACK, but it is workaround - and
the enhancing of GET DIAGNOSTICS was not designed for this purpose. Sure,
there are more variant of fixing - and we can implement more than one.

Regards

Pavel

David J.

------------------------------
If you reply to this email, your message will be added to the
discussion below:

http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382p5844393.html
To unsubscribe from Why doesn't `RAISE EXCEPTION` provide error
context?, click here.
NAML
<http://postgresql.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&amp;id=instant_html%21nabble%3Aemail.naml&amp;base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&amp;breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml&gt;

------------------------------
View this message in context: Re: Why doesn't `RAISE EXCEPTION` provide
error context?
<http://postgresql.nabble.com/Why-doesn-t-RAISE-EXCEPTION-provide-error-context-tp5844382p5844473.html&gt;
Sent from the PostgreSQL - general mailing list archive
<http://postgresql.nabble.com/PostgreSQL-general-f1843780.html&gt; at
Nabble.com.

--
*Melvin Davidson*
I reserve the right to fantasize. Whether or not you
wish to share my fantasy is entirely up to you.

#9Alban Hertroys
haramrae@gmail.com
In reply to: Taytay (#8)
Re: Why doesn't `RAISE EXCEPTION` provide error context?

On 2 April 2015 at 19:15, Taylor Brown <taylor@youneedabudget.com> wrote:

So, I would rather put a check like this at the top of my function:

--
important_variable = (p_request::json->>'important_variable')::integer;
IF (important_variable is NULL) THEN RAISE EXCEPTION 'important_variable
must not be NULL.'; END IF;
--

But I won't be able to get the context for that exception, and all I'll be
able to return from the function or write to the logs is
'important_variable must not be NULL.'. If that's the only place I throw
that error, I'll know where to look. Otherwise, I have no context, and
won't be able to determine where my exception was thrown. So I'm actually
better off _not_ throwing my own custom exceptions, even though I would
prefer to be more defensive about this sort of thing in my code.

I thought I might be able to "trick" postgres into throwing another
unrelated exception that would not only include my custom error message,
but allow me to extract the context, telling me the function where I should
begin debugging.

Just a quick idea, but... Perhaps you could put a constraint on those JSON
messages indirectly, by mapping it to some kind of template table?
The top-level of a JSON message can usually be mapped to a table, and a
table can have constraints and, for example, a BEFORE INSERT trigger that
always returns NULL so that the data is not actually inserted into the
table.

--
If you can't see the forest for the trees,
Cut the trees and you'll see there is no forest.