Skip to content

fix(db): memoise InvalidNameError GUC rejections like UndefinedObjectError - #3826

Open
Andreymi wants to merge 1 commit into
vectorize-io:mainfrom
Andreymi:fix/guc-invalid-name-rejection
Open

fix(db): memoise InvalidNameError GUC rejections like UndefinedObjectError#3826
Andreymi wants to merge 1 commit into
vectorize-io:mainfrom
Andreymi:fix/guc-invalid-name-rejection

Conversation

@Andreymi

Copy link
Copy Markdown
Contributor

The problem

apply_session_settings' individual-fallback path remembers a GUC the server rejected (_unsupported_settings) so it is never sent again — but only when the rejection is UndefinedObjectError (42704, unrecognized configuration parameter).

A server whose loaded extension has reserved the prefix answers differently: InvalidNameError (42602, invalid configuration parameter name). pgvector 0.6.0 does exactly that for hnsw.iterative_scan, which it predates.

That rejection falls through to the broad PostgresError arm (debug log, retry next acquire), so the name is never memoised and setting_rejected_by_server() keeps answering False. The consequence is worse than the re-probing burn (#3499): retain's ANN link probing trusts that check before SET LOCAL inside its own transaction — so on pgvector < 0.8 every retain aborts its whole link computation:

asyncpg.exceptions.InvalidNameError: invalid configuration parameter name "hnsw.iterative_scan"

Facts still store and recall stays green, so the degradation is silent — the designed fallback (skip the GUC, keep linking) never engages. Observed in production on PG16 + pgvector 0.6.0 after upgrading to v0.9.2: 18 aborted link passes in three hours, zero user-visible errors.

The fix

Treat both error classes as the permanent verdicts they are:

except (asyncpg.exceptions.UndefinedObjectError, asyncpg.exceptions.InvalidNameError):

The except stays narrow — no bare PostgresError — so transient failures keep retrying, exactly as test_a_transient_failure_does_not_disable_a_setting requires.

Test

test_invalid_name_rejection_is_remembered_like_undefined_object drives the exact production exception through apply_session_settings and asserts the memo catches it (fails on current main, passes with the fix). The existing test_a_setting_the_server_rejects_is_not_sent_again already names this very scenario in its docstring — "hnsw.iterative_scan on a pgvector older than 0.8" — but models the server with UndefinedObjectError; the new test covers what such a server actually raises. _RecordingConnection gains a reject_error parameter (default unchanged).

Notes

HINDSIGHT_API_ANN_ITERATIVE_SCAN=false works as an operational kill-switch meanwhile — this change makes the automatic degradation work as designed, so old-pgvector deployments don't need to know about the flag.

…Error

The session-setup fallback remembers a GUC the server rejected so it is
never sent again — but only when the rejection is UndefinedObjectError
(42704, "unrecognized configuration parameter"). A server whose loaded
extension has reserved the prefix answers InvalidNameError instead (42602,
"invalid configuration parameter name"): pgvector 0.6.0 does exactly that
for hnsw.iterative_scan, which it predates.

That rejection fell through to the broad PostgresError arm, so the name was
never memoised and setting_rejected_by_server() kept answering False. The
consequence is worse than the re-probing burn (vectorize-io#3499): retain's ANN link
probing trusts that check before SET LOCAL inside its own transaction, so
on pgvector < 0.8 every retain aborted its whole link computation with

    asyncpg.exceptions.InvalidNameError: invalid configuration parameter
    name "hnsw.iterative_scan"

while facts stored and recall stayed green — the designed degradation
(skip the GUC, keep linking) never engaged. Observed in production on
PG16 + pgvector 0.6.0 after upgrading to v0.9.2, 18 aborted link passes
in three hours.

Both error classes are permanent verdicts for a given server, so both are
now memoised; the except stays narrow so transient failures keep retrying.
The test drives the exact production exception through
apply_session_settings and asserts the memo catches it.
@strix-security

strix-security Bot commented Aug 26, 2026

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Updated for 107b3d5.


Reviewed by Strix
Re-run review · Configure security review settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant