fix(db): memoise InvalidNameError GUC rejections like UndefinedObjectError - #3826
Open
Andreymi wants to merge 1 commit into
Open
fix(db): memoise InvalidNameError GUC rejections like UndefinedObjectError#3826Andreymi wants to merge 1 commit into
Andreymi wants to merge 1 commit into
Conversation
…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 ReviewNo security issues found. Updated for Reviewed by Strix |
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.
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 isUndefinedObjectError(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 forhnsw.iterative_scan, which it predates.That rejection falls through to the broad
PostgresErrorarm (debug log, retry next acquire), so the name is never memoised andsetting_rejected_by_server()keeps answeringFalse. The consequence is worse than the re-probing burn (#3499): retain's ANN link probing trusts that check beforeSET LOCALinside its own transaction — so on pgvector < 0.8 every retain aborts its whole link computation: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:
The except stays narrow — no bare
PostgresError— so transient failures keep retrying, exactly astest_a_transient_failure_does_not_disable_a_settingrequires.Test
test_invalid_name_rejection_is_remembered_like_undefined_objectdrives the exact production exception throughapply_session_settingsand asserts the memo catches it (fails on current main, passes with the fix). The existingtest_a_setting_the_server_rejects_is_not_sent_againalready names this very scenario in its docstring — "hnsw.iterative_scan on a pgvector older than 0.8" — but models the server withUndefinedObjectError; the new test covers what such a server actually raises._RecordingConnectiongains areject_errorparameter (default unchanged).Notes
HINDSIGHT_API_ANN_ITERATIVE_SCAN=falseworks 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.