WAIT FOR NO_THROW option could use some documentation

Started by Peter Eisentraut9 days ago16 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253621
psql -h localhost -U postgres

Built from patchset v16 (message #16), September 09, 2026 at 04:14 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253621_16 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253621_16 && git checkout t253621_16

Patchset v16 (message #16) is on t253621_16

Jump to latest
#1Peter Eisentraut
peter_e@gmx.net

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not). I suspect this option was added with some particular
client control flow in mind, but I think this needs to be explained
somewhere.

#2Rithvika Devisetti
devisettirithvika@gmail.com
In reply to: Peter Eisentraut (#1)
Re: WAIT FOR NO_THROW option could use some documentation

On Sun, 2026-08-31 at 07:47 +0200, Peter Eisentraut wrote:

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not).

Hello,

Attached is a patch.

The reason I settled on is that the difference is transactional. The
error raised without NO_THROW aborts the current transaction, so a
caller that treats a timeout as recoverable (retry, fall back to the
primary, report the delay) has to roll back first and discard whatever
else that transaction had done. With NO_THROW the session is
unaffected and the caller can branch on the returned status. I
confirmed this: a timeout inside a transaction block leaves it aborted,
while the same wait with NO_THROW leaves the session usable.

Regards,
Rithvika Devisetti

On Mon, Aug 31, 2026 at 7:47 AM Peter Eisentraut <peter@eisentraut.org>
wrote:

Show quoted text

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not). I suspect this option was added with some particular
client control flow in mind, but I think this needs to be explained
somewhere.

Attachments:

t253621_2
0001-doc-Explain-when-to-use-the-WAIT-FOR-NO_THROW-option.patchapplication/octet-stream; name=0001-doc-Explain-when-to-use-the-WAIT-FOR-NO_THROW-option.patchDownload+18-1
#3Kiran Kaki
itskkpg@gmail.com
In reply to: Rithvika Devisetti (#2)
Re: WAIT FOR NO_THROW option could use some documentation

Hi Rithvika,

Thanks for the patch, that was a quick turnaround. The examples of
retrying the wait or directing
subsequent reads to the primary explain the intended client control flow
and address Peter's concern.

+          The error raised otherwise aborts the current
+          transaction, so a caller that responds to a timeout by waiting
+          again or reading from the primary instead would have to roll

back

+ and discard any work already done.

This seems a little too broad. If WAIT FOR is executed after a
savepoint, the application can recover using ROLLBACK TO SAVEPOINT
without discarding work performed before the savepoint. Previously
committed work is also unaffected when the command is executed in
autocommit mode.

As a suggestion, perhaps this part could say:

* Use this option when a timeout or the server not being in recovery
is an expected outcome that the application can handle, for example by
retrying the wait or directing subsequent reads to the primary. Without
this option, either outcome raises an error. Within a transaction
block, the application must then roll back the transaction or roll back
to a savepoint before issuing further commands.*

+ This option affects only the outcome of the wait. Conditions

that

+ prevent the command from running at all still raise an error,

and

+          the wait is still unbounded unless
+          <literal>TIMEOUT</literal> is also specified.

This distinction is useful. I suggest saying "changes only how these
wait outcomes are reported" instead of "affects only the outcome",
since NO_THROW changes the reporting behavior rather than the outcome
of the wait itself.

As a suggestion, this could read:

* This option changes only how these wait outcomes are reported.
Errors that prevent the command from running are still raised. The
option also does not limit how long the command waits; specify TIMEOUT
to bound the wait.*

Regards,
Kiran Kaki

On Mon, Aug 31, 2026 at 11:39 AM Rithvika Devisetti <
devisettirithvika@gmail.com> wrote:

Show quoted text

On Sun, 2026-08-31 at 07:47 +0200, Peter Eisentraut wrote:

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not).

Hello,

Attached is a patch.

The reason I settled on is that the difference is transactional. The
error raised without NO_THROW aborts the current transaction, so a
caller that treats a timeout as recoverable (retry, fall back to the
primary, report the delay) has to roll back first and discard whatever
else that transaction had done. With NO_THROW the session is
unaffected and the caller can branch on the returned status. I
confirmed this: a timeout inside a transaction block leaves it aborted,
while the same wait with NO_THROW leaves the session usable.

Regards,
Rithvika Devisetti

On Mon, Aug 31, 2026 at 7:47 AM Peter Eisentraut <peter@eisentraut.org>
wrote:

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not). I suspect this option was added with some particular
client control flow in mind, but I think this needs to be explained
somewhere.

#4Xuneng Zhou
xunengzhou@gmail.com
In reply to: Kiran Kaki (#3)
Re: WAIT FOR NO_THROW option could use some documentation

Hi,

Thanks for raising this and proposing the patch!

On Tue, Sep 1, 2026 at 6:26 AM Kiran Kaki <itskkpg@gmail.com> wrote:

Hi Rithvika,

Thanks for the patch, that was a quick turnaround. The examples of retrying the wait or directing
subsequent reads to the primary explain the intended client control flow
and address Peter's concern.

+          The error raised otherwise aborts the current
+          transaction, so a caller that responds to a timeout by waiting
+          again or reading from the primary instead would have to roll back
+          and discard any work already done.

This seems a little too broad. If WAIT FOR is executed after a
savepoint, the application can recover using ROLLBACK TO SAVEPOINT
without discarding work performed before the savepoint. Previously
committed work is also unaffected when the command is executed in
autocommit mode.

As a suggestion, perhaps this part could say:

Use this option when a timeout or the server not being in recovery
is an expected outcome that the application can handle, for example
by retrying the wait or directing subsequent reads to the primary.
Without this option, either outcome raises an error. Within a
transaction block, the application must then roll back the
transaction or roll back to a savepoint before issuing further
commands.

+ 1. I prefer this direction more.

+          This option affects only the outcome of the wait.  Conditions that
+          prevent the command from running at all still raise an error, and
+          the wait is still unbounded unless
+          <literal>TIMEOUT</literal> is also specified.

This distinction is useful. I suggest saying "changes only how these
wait outcomes are reported" instead of "affects only the outcome",
since NO_THROW changes the reporting behavior rather than the outcome
of the wait itself.

As a suggestion, this could read:

This option changes only how these wait outcomes are reported.
Errors that prevent the command from running are still raised.
The option also does not limit how long the command waits; specify
TIMEOUT to bound the wait.

These lines seem to be useful.

Regards,
Kiran Kaki

On Mon, Aug 31, 2026 at 11:39 AM Rithvika Devisetti <devisettirithvika@gmail.com> wrote:

On Sun, 2026-08-31 at 07:47 +0200, Peter Eisentraut wrote:

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not).

Hello,

Attached is a patch.

The reason I settled on is that the difference is transactional. The
error raised without NO_THROW aborts the current transaction, so a
caller that treats a timeout as recoverable (retry, fall back to the
primary, report the delay) has to roll back first and discard whatever
else that transaction had done. With NO_THROW the session is
unaffected and the caller can branch on the returned status. I
confirmed this: a timeout inside a transaction block leaves it aborted,
while the same wait with NO_THROW leaves the session usable.

Regards,
Rithvika Devisetti

On Mon, Aug 31, 2026 at 7:47 AM Peter Eisentraut <peter@eisentraut.org> wrote:

I don't find any documentation for the WAIT FOR NO_THROW option other
than a few short sentences in the man page about what it does
technically. But I don't find anything about why one would want to use
it (or not). I suspect this option was added with some particular
client control flow in mind, but I think this needs to be explained
somewhere.

I am not the author who added the option. So the following are just
some random guesses for the motivation of introducing it after doing
some archeological works[1]/messages/by-id/ZtUF17gF0pNpwZDI@paquier.xyz [2]/messages/by-id/E1t3wZa-002Dtg-PT@gemulon.postgresql.org [3]/messages/by-id/CAPpHfduN68AzUHvzzPG80qwa-27QXjd820tzcjoUk2Tc6_O=5A@mail.gmail.com [4]/messages/by-id/CAPpHfdt5VCM1DoodvVoiRUaoRuXrNEzAmrMQ-eLa0E7wByXaKw@mail.gmail.com.

Different return statuses were introduced so that an application could
determine why a wait ended. Reaching the target LSN, reaching the
timeout, and discovering that the server is no longer in recovery are
operationally different results. Reporting them as 'success',
'timeout', and 'not in recovery' gives clients a stable,
machine-readable interface instead of forcing them to parse error
messages, which may also be localized.

'NO_THROW' was added to make those statuses available for ordinary
application control flow. Without it, 'timeout' and 'not in recovery'
are raised as SQL errors. With it, they are returned as status values,
allowing the application to retry, report replication lag, refresh its
routing information, or direct a subsequent read to the primary. In
that sense, 'NO_THROW' selects how these expected wait outcomes are
reported: through the error channel or through the result row.

Avoiding an aborted transaction is a secondary benefit. When
'NO_THROW' returns a status, an explicit transaction remains usable;
otherwise, the application must roll back the transaction or to a
savepoint. But transaction preservation was not the principal
motivation. Without distinct return statuses, merely suppressing
errors would be of little use because the application would not know
whether the target LSN had actually been reached.

[This piece is written and revised by Sol from my instructions. I
don't have enough time to write a version of mine.]

[1]: /messages/by-id/ZtUF17gF0pNpwZDI@paquier.xyz
[2]: /messages/by-id/E1t3wZa-002Dtg-PT@gemulon.postgresql.org
[3]: /messages/by-id/CAPpHfduN68AzUHvzzPG80qwa-27QXjd820tzcjoUk2Tc6_O=5A@mail.gmail.com
[4]: /messages/by-id/CAPpHfdt5VCM1DoodvVoiRUaoRuXrNEzAmrMQ-eLa0E7wByXaKw@mail.gmail.com

One side-note -- please read the section related to top-posting in this page:

"Finally, our community generally does not "top post" in response to
mailing list threads (See Wikipedia: Top Postingfor a definition of
top posting, and Top Posting Deprecated for discussion of why we
discourage it)."

https://wiki.postgresql.org/wiki/Mailing_Lists

--
Regards,
Xuneng Zhou
HighGo Software Co., Ltd.

#5Kiran Kaki
itskkpg@gmail.com
In reply to: Xuneng Zhou (#4)
Re: WAIT FOR NO_THROW option could use some documentation

Hi

On Mon, Aug 31, 2026 at 11:28 PM Xuneng Zhou <xunengzhou@gmail.com> wrote:

I am not the author who added the option. So the following are just
some random guesses for the motivation of introducing it after doing
some archeological works[1] [2] [3] [4].

Different return statuses were introduced so that an application could
determine why a wait ended. Reaching the target LSN, reaching the
timeout, and discovering that the server is no longer in recovery are
operationally different results. Reporting them as 'success',
'timeout', and 'not in recovery' gives clients a stable,
machine-readable interface instead of forcing them to parse error
messages, which may also be localized.

'NO_THROW' was added to make those statuses available for ordinary
application control flow. Without it, 'timeout' and 'not in recovery'
are raised as SQL errors. With it, they are returned as status values,
allowing the application to retry, report replication lag, refresh its
routing information, or direct a subsequent read to the primary. In
that sense, 'NO_THROW' selects how these expected wait outcomes are
reported: through the error channel or through the result row.

Avoiding an aborted transaction is a secondary benefit. When
'NO_THROW' returns a status, an explicit transaction remains usable;
otherwise, the application must roll back the transaction or to a
savepoint. But transaction preservation was not the principal
motivation. Without distinct return statuses, merely suppressing
errors would be of little use because the application would not know
whether the target LSN had actually been reached.

[This piece is written and revised by Sol from my instructions. I
don't have enough time to write a version of mine.]

Thanks for looking into the history and clarifying the original
motivation. The distinction between returning the wait outcome through
a result row and keeping the transaction usable is helpful. I agree
that the documentation should emphasize machine-readable statuses and
application control flow as the primary motivation, while mentioning
transaction preservation as a secondary benefit.

Regards,
Kiran Kaki
.

#6Peter Eisentraut
peter_e@gmx.net
In reply to: Xuneng Zhou (#4)
Re: WAIT FOR NO_THROW option could use some documentation

On 01.09.26 08:28, Xuneng Zhou wrote:

'NO_THROW' was added to make those statuses available for ordinary
application control flow. Without it, 'timeout' and 'not in recovery'
are raised as SQL errors. With it, they are returned as status values,
allowing the application to retry, report replication lag, refresh its
routing information, or direct a subsequent read to the primary. In
that sense, 'NO_THROW' selects how these expected wait outcomes are
reported: through the error channel or through the result row.

This just explains the technical distinction, not why it's needed.
Applications or client frameworks could just as well inspect an error
return with for example an appropriate error code. That's what they'd d
for any other command.

#7Xuneng Zhou
xunengzhou@gmail.com
In reply to: Peter Eisentraut (#6)
Re: WAIT FOR NO_THROW option could use some documentation

Hi Peter,

On Thu, Sep 3, 2026 at 4:05 AM Peter Eisentraut <peter@eisentraut.org> wrote:

On 01.09.26 08:28, Xuneng Zhou wrote:

'NO_THROW' was added to make those statuses available for ordinary
application control flow. Without it, 'timeout' and 'not in recovery'
are raised as SQL errors. With it, they are returned as status values,
allowing the application to retry, report replication lag, refresh its
routing information, or direct a subsequent read to the primary. In
that sense, 'NO_THROW' selects how these expected wait outcomes are
reported: through the error channel or through the result row.

This just explains the technical distinction, not why it's needed.
Applications or client frameworks could just as well inspect an error
return with for example an appropriate error code. That's what they'd d
for any other command.

That's interesting. I was unaware of the use of error codes as the
states of application logical control flow. But that use seems not
elegant to me or maybe I misunderstood its usage.

ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
ERRCODE_QUERY_CANCELED

These error codes are overloaded in terms of meaning and the
conditions lead to each. They are not tailed for the return states of
WAIT FOR. If I was a user, I would be less happy to figure out what
they mean and what they are represented for.

errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is not in progress"),

errcode + errmsg together seems to be a more sensible state, but it
would require extra parsing effort.

But this alone seems not warrant a standalone option. The direction
that Rithvika put earlier now makes more sense to me. But I would
suggest adjusting its expression and adding examples. I'll reply later
while I get more time.

--
Regards,
Xuneng Zhou
HighGo Software Co., Ltd.

#8SATYANARAYANA NARLAPURAM
satyanarlapuram@gmail.com
In reply to: Xuneng Zhou (#7)
Re: WAIT FOR NO_THROW option could use some documentation

Hi,

On Thu, Sep 3, 2026 at 1:10 AM Xuneng Zhou <xunengzhou@gmail.com> wrote:

Hi Peter,

On Thu, Sep 3, 2026 at 4:05 AM Peter Eisentraut <peter@eisentraut.org>
wrote:

On 01.09.26 08:28, Xuneng Zhou wrote:

'NO_THROW' was added to make those statuses available for ordinary
application control flow. Without it, 'timeout' and 'not in recovery'
are raised as SQL errors. With it, they are returned as status values,
allowing the application to retry, report replication lag, refresh its
routing information, or direct a subsequent read to the primary. In
that sense, 'NO_THROW' selects how these expected wait outcomes are
reported: through the error channel or through the result row.

This just explains the technical distinction, not why it's needed.
Applications or client frameworks could just as well inspect an error
return with for example an appropriate error code. That's what they'd d
for any other command.

That's interesting. I was unaware of the use of error codes as the
states of application logical control flow. But that use seems not
elegant to me or maybe I misunderstood its usage.

ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
ERRCODE_QUERY_CANCELED

These error codes are overloaded in terms of meaning and the
conditions lead to each. They are not tailed for the return states of
WAIT FOR. If I was a user, I would be less happy to figure out what
they mean and what they are represented for.

errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is not in progress"),

errcode + errmsg together seems to be a more sensible state, but it
would require extra parsing effort.

But this alone seems not warrant a standalone option. The direction
that Rithvika put earlier now makes more sense to me. But I would
suggest adjusting its expression and adding examples. I'll reply later
while I get more time.

Maybe something along these lines - "NO_THROW option safely prevents the
database
from aborting an active transaction, allowing subsequent queries within the
transaction
to proceed without losing prior work"?

Thanks,
Satya

#9Peter Eisentraut
peter_e@gmx.net
In reply to: SATYANARAYANA NARLAPURAM (#8)
Re: WAIT FOR NO_THROW option could use some documentation

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely prevents the
database
from aborting an active transaction, allowing subsequent queries within
the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to the
client but not abort the transaction on the server.

#10SATYANARAYANA NARLAPURAM
satyanarlapuram@gmail.com
In reply to: Peter Eisentraut (#9)
Re: WAIT FOR NO_THROW option could use some documentation

Hi,

On Thu, Sep 3, 2026 at 1:39 PM Peter Eisentraut <peter@eisentraut.org>
wrote:

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely prevents the
database
from aborting an active transaction, allowing subsequent queries within
the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to the
client but not abort the transaction on the server.

Curious, Is there an existing precedent for this in the core where we send
an error
but not abort a transaction on the server? Parsing error messages is
painful compared
to reading the result set it seems.

Additionally, I see the information passed to the client when an error is
thrown much richer
than a row returned like timeout. Perhaps if we decide to support NO_THROW
should
we consider adding a current replay LSN as well?

postgres=# WAIT FOR LSN '0/306EE20' WITH (TIMEOUT '0.1s');
ERROR: timed out while waiting for target LSN 0/306EE20 to be replayed;
current replay LSN 0/306EA60

postgres=# WAIT FOR LSN '0/306EE20' WITH (TIMEOUT '100ms', NO_THROW);
status
---------
timeout
(1 row)

Thanks,
Satya

#11Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#9)
Re: WAIT FOR NO_THROW option could use some documentation

On Thu, Sep 3, 2026 at 4:39 PM Peter Eisentraut <peter@eisentraut.org> wrote:

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely prevents the
database
from aborting an active transaction, allowing subsequent queries within
the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to the
client but not abort the transaction on the server.

I think sending an error without aborting the transaction on the
server would invite too much confusion. But I also wonder if the
documentation's claim that this option will just cause the server to
categorically not throw errors can really be correct. In most places
where we have an error-suppression facility of some kind, it's much
more narrowly scoped.

--
Robert Haas
EDB: http://www.enterprisedb.com

#12SATYANARAYANA NARLAPURAM
satyanarlapuram@gmail.com
In reply to: Robert Haas (#11)
Re: WAIT FOR NO_THROW option could use some documentation

On Thu, Sep 3, 2026 at 4:20 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Sep 3, 2026 at 4:39 PM Peter Eisentraut <peter@eisentraut.org>
wrote:

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely prevents

the

database
from aborting an active transaction, allowing subsequent queries within
the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to the
client but not abort the transaction on the server.

I think sending an error without aborting the transaction on the
server would invite too much confusion. But I also wonder if the
documentation's claim that this option will just cause the server to
categorically not throw errors can really be correct. In most places
where we have an error-suppression facility of some kind, it's much
more narrowly scoped.

Agree with Robert on this. I would say the error suppression is narrow here
as well.
When an incorrect mode or LSN is provided, it throws an error even with the
NO_THROW option.

postgres=# WAIT FOR LSN '0/306EEk0' WITH (TIMEOUT '100ms', NO_THROW, MODE
primary_flush);
ERROR: invalid input syntax for type pg_lsn: "0/306EEk0"
postgres=# WAIT FOR LSN '0/306EE0' WITH (TIMEOUT '100ms', NO_THROW, MODE
primary_flush2);
ERROR: unrecognized value for WAIT option "mode": "primary_flush2"

#13Xuneng Zhou
xunengzhou@gmail.com
In reply to: SATYANARAYANA NARLAPURAM (#10)
Re: WAIT FOR NO_THROW option could use some documentation

Hi Satya,

On Fri, Sep 4, 2026 at 7:00 AM SATYANARAYANA NARLAPURAM
<satyanarlapuram@gmail.com> wrote:

Hi,

On Thu, Sep 3, 2026 at 1:39 PM Peter Eisentraut <peter@eisentraut.org> wrote:

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely prevents the
database
from aborting an active transaction, allowing subsequent queries within
the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to the
client but not abort the transaction on the server.

Curious, Is there an existing precedent for this in the core where we send an error
but not abort a transaction on the server? Parsing error messages is painful compared
to reading the result set it seems.

I asked Sol to investigate this, and it said it did not find one.

Additionally, I see the information passed to the client when an error is thrown much richer
than a row returned like timeout. Perhaps if we decide to support NO_THROW should
we consider adding a current replay LSN as well?

I think this depends on how applications are expected to use the
result. If the primary use of it is states for application control
flow, then the brevity seems good to me. For extended diagnostic or
monitoring purposes, adding a companioning LSN might make sense.
Humans might prefer richer messages if they would look at it, but it
might not necessarily be the interface an application should have to
parse.I don't know how users would actually use it.

postgres=# WAIT FOR LSN '0/306EE20' WITH (TIMEOUT '0.1s');
ERROR: timed out while waiting for target LSN 0/306EE20 to be replayed; current replay LSN 0/306EA60

postgres=# WAIT FOR LSN '0/306EE20' WITH (TIMEOUT '100ms', NO_THROW);
status
---------
timeout
(1 row)

Thanks,
Satya

--
Regards,
Xuneng Zhou
HighGo Software Co., Ltd.

#14Xuneng Zhou
xunengzhou@gmail.com
In reply to: SATYANARAYANA NARLAPURAM (#8)
Re: WAIT FOR NO_THROW option could use some documentation

On Thu, Sep 3, 2026 at 11:21 PM SATYANARAYANA NARLAPURAM <
satyanarlapuram@gmail.com> wrote:

Hi,

On Thu, Sep 3, 2026 at 1:10 AM Xuneng Zhou <xunengzhou@gmail.com> wrote:

Hi Peter,

On Thu, Sep 3, 2026 at 4:05 AM Peter Eisentraut <peter@eisentraut.org>

wrote:

On 01.09.26 08:28, Xuneng Zhou wrote:

'NO_THROW' was added to make those statuses available for ordinary
application control flow. Without it, 'timeout' and 'not in recovery'
are raised as SQL errors. With it, they are returned as status

values,

allowing the application to retry, report replication lag, refresh

its

routing information, or direct a subsequent read to the primary. In
that sense, 'NO_THROW' selects how these expected wait outcomes are
reported: through the error channel or through the result row.

This just explains the technical distinction, not why it's needed.
Applications or client frameworks could just as well inspect an error
return with for example an appropriate error code. That's what they'd

d

for any other command.

That's interesting. I was unaware of the use of error codes as the
states of application logical control flow. But that use seems not
elegant to me or maybe I misunderstood its usage.

ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
ERRCODE_QUERY_CANCELED

These error codes are overloaded in terms of meaning and the
conditions lead to each. They are not tailed for the return states of
WAIT FOR. If I was a user, I would be less happy to figure out what
they mean and what they are represented for.

errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is not in progress"),

errcode + errmsg together seems to be a more sensible state, but it
would require extra parsing effort.

But this alone seems not warrant a standalone option. The direction
that Rithvika put earlier now makes more sense to me. But I would
suggest adjusting its expression and adding examples. I'll reply later
while I get more time.

Maybe something along these lines - "NO_THROW option safely prevents the

database

from aborting an active transaction, allowing subsequent queries within

the transaction

to proceed without losing prior work"?

Thanks for the suggestion. I guess that this is the main differentiater
from other alternatives.

As Robert and you pointed out earlier -- no_throw cannot suppress all
errors. I think it's true. Then the first part of the para may be too broad
-- it cannot protect everything -- some errors still abort txn. I am also
wondering whether we need to emphasize "why no_throw is genuinely needed"
over "when/how to use it". Yeah, there are alternatives to achieve almost
the same thing(maybe less graceful) like riding a horse or car can both go
to a place (may not be a good analogy). Do users really care that much why
a car is better than a horse in what aspects and why do they want a car
even they have a horse? If we offer them an option, we might want to tell
them when/how to use it just like a car manual won't have much
material about why it is unreplaceble from and superior to its peers.

If that make sense, I found the version that Kiran suggested to be useful.
Here's a edited version on that:

Use NO_THROW when timeout or not in recovery is an expected result that the
application intends to handle, for example by retrying the wait, reporting
replication delay, or choosing another server for a subsequent operation.
The command then returns the result as a status, which the application must
check before assuming that the target LSN was reached. Omit NO_THROW when
the application must not proceed unless the target LSN is reached, so that
an unsuccessful wait stops normal execution with an error. Returning a
status also leaves an explicit transaction usable; without NO_THROW, the
corresponding error requires rollback of the transaction or to a savepoint
before further commands can be issued. NO_THROW changes only how timeout
and not in recovery are reported; other errors are still raised. It does
not limit the duration of the wait; specify TIMEOUT for that purpose.

WDT?

---
Regards,
Xuneng Zhou
HighGo Software Co., Ltd.

#15Xuneng Zhou
xunengzhou@gmail.com
In reply to: SATYANARAYANA NARLAPURAM (#12)
Re: WAIT FOR NO_THROW option could use some documentation

On Fri, Sep 4, 2026 at 8:26 AM SATYANARAYANA NARLAPURAM <
satyanarlapuram@gmail.com> wrote:

On Thu, Sep 3, 2026 at 4:20 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Sep 3, 2026 at 4:39 PM Peter Eisentraut <peter@eisentraut.org>

wrote:

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely prevents

the

database
from aborting an active transaction, allowing subsequent queries

within

the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to the
client but not abort the transaction on the server.

I think sending an error without aborting the transaction on the
server would invite too much confusion. But I also wonder if the
documentation's claim that this option will just cause the server to
categorically not throw errors can really be correct. In most places
where we have an error-suppression facility of some kind, it's much
more narrowly scoped.

Agree with Robert on this. I would say the error suppression is narrow

here as well.

Yeah, I also think Robert is right for not claiming it absolutely.

"If NO_THROW is specified, the command returns a status string instead of
throwing errors."

We may need to soften this line.

When an incorrect mode or LSN is provided, it throws an error even with

the NO_THROW option.

postgres=# WAIT FOR LSN '0/306EEk0' WITH (TIMEOUT '100ms', NO_THROW, MODE

primary_flush);

ERROR: invalid input syntax for type pg_lsn: "0/306EEk0"
postgres=# WAIT FOR LSN '0/306EE0' WITH (TIMEOUT '100ms', NO_THROW, MODE

primary_flush2);

ERROR: unrecognized value for WAIT option "mode": "primary_flush2"

Thanks for testing this. I agree that the behavior is not aligned with the
description of doc. The behavior itself seems fine to me, what we need to
change is the doc. These errors are not supposed to be suppressed because
they are not valid inputs in the first place. Another one error needs
consideration is primary_flush waiting in standby. Currently, we prevent
this use by erroring out before entering the wait, hence no_throw option
cannot suppress it. I think this behavior is fine. To suppressithat error
implies that we want a new return status like 'in recovery' after valid
waiting. However, that needs seems not true because we don't expect a
primary being demoted to a standby. We might still need extra description
for it.

--
Regards,
Xuneng Zhou
HighGo Software Co., Ltd.

#16Rithvika Devisetti
devisettirithvika@gmail.com
In reply to: Xuneng Zhou (#15)
Re: WAIT FOR NO_THROW option could use some documentation

Thank you everyone for the suggestions.
v3 attached, folding in the remaining points.

The description now says the command "reports these outcomes as a
status string instead of raising an error", tying it to the timeout and
promotion cases named just above rather than claiming suppression
generally.

The option entry uses the consolidated wording from earlier in the
thread, and its last paragraph now names what still errors: invalid
inputs (Satya's malformed-LSN and unrecognized-mode examples), and
requesting primary_flush during recovery, which is rejected before the
wait begins, per Xuneng's note.

On Sat, Sep 5, 2026 at 12:23 AM Xuneng Zhou <xunengzhou@gmail.com> wrote:

Show quoted text

On Fri, Sep 4, 2026 at 8:26 AM SATYANARAYANA NARLAPURAM <
satyanarlapuram@gmail.com> wrote:

On Thu, Sep 3, 2026 at 4:20 PM Robert Haas <robertmhaas@gmail.com>

wrote:

On Thu, Sep 3, 2026 at 4:39 PM Peter Eisentraut <peter@eisentraut.org>

wrote:

On 03.09.26 17:21, SATYANARAYANA NARLAPURAM wrote:

Maybe something along these lines - "NO_THROW option safely

prevents the

database
from aborting an active transaction, allowing subsequent queries

within

the transaction
to proceed without losing prior work"?

Maybe that's what it is meant for, but that seems separate from the
status reporting mechanism. It could also send an error message to

the

client but not abort the transaction on the server.

I think sending an error without aborting the transaction on the
server would invite too much confusion. But I also wonder if the
documentation's claim that this option will just cause the server to
categorically not throw errors can really be correct. In most places
where we have an error-suppression facility of some kind, it's much
more narrowly scoped.

Agree with Robert on this. I would say the error suppression is narrow

here as well.

Yeah, I also think Robert is right for not claiming it absolutely.

"If NO_THROW is specified, the command returns a status string instead of
throwing errors."

We may need to soften this line.

When an incorrect mode or LSN is provided, it throws an error even with

the NO_THROW option.

postgres=# WAIT FOR LSN '0/306EEk0' WITH (TIMEOUT '100ms', NO_THROW,

MODE primary_flush);

ERROR: invalid input syntax for type pg_lsn: "0/306EEk0"
postgres=# WAIT FOR LSN '0/306EE0' WITH (TIMEOUT '100ms', NO_THROW, MODE

primary_flush2);

ERROR: unrecognized value for WAIT option "mode": "primary_flush2"

Thanks for testing this. I agree that the behavior is not aligned with the
description of doc. The behavior itself seems fine to me, what we need to
change is the doc. These errors are not supposed to be suppressed because
they are not valid inputs in the first place. Another one error needs
consideration is primary_flush waiting in standby. Currently, we prevent
this use by erroring out before entering the wait, hence no_throw option
cannot suppress it. I think this behavior is fine. To suppressithat error
implies that we want a new return status like 'in recovery' after valid
waiting. However, that needs seems not true because we don't expect a
primary being demoted to a standby. We might still need extra description
for it.

--
Regards,
Xuneng Zhou
HighGo Software Co., Ltd.

Attachments:

t253621_16
v3-0001-doc-Explain-when-to-use-the-WAIT-FOR-NO_THROW-op.patchapplication/octet-stream; name=v3-0001-doc-Explain-when-to-use-the-WAIT-FOR-NO_THROW-op.patchDownload+33-3