Skip to content

fix: catch tsquery syntax errors (42601) as ValidationError in search queries#3713

Open
capJavert wants to merge 2 commits intomainfrom
eng-1077-catch-tsquery-syntax-errors-42601-as-validationerror-in
Open

fix: catch tsquery syntax errors (42601) as ValidationError in search queries#3713
capJavert wants to merge 2 commits intomainfrom
eng-1077-catch-tsquery-syntax-errors-42601-as-validationerror-in

Conversation

@capJavert
Copy link
Contributor

Summary

  • Harden processSearchQuery to strip tsquery metacharacters (& | ! ( ) < > : *) from user input before constructing the query string, preventing invalid to_tsquery SQL
  • Add try/catch safety net at all four search execution points to catch any remaining 42601 errors and return ValidationError instead of UNEXPECTED
  • Add SYNTAX_ERROR = '42601' to TypeOrmError enum with shared handleSearchQueryError helper

Key decisions

  • Keep to_tsquery with :* prefix matchingwebsearch_to_tsquery/plainto_tsquery don't support :*, which is required for autocomplete
  • Two-layer defense — sanitization prevents most errors; try/catch is belt-and-suspenders for edge cases
  • Strip metacharacters, don't reject — users get useful results from sanitized input rather than errors for queries like react & vue
  • Throw ValidationError for empty-after-strip — inputs like & | ! that become empty after stripping get a clean validation error

Search paths covered

  1. searchBookmarksSuggestions (raw SQL)
  2. searchBookmarks (feed resolver)
  3. searchReadingHistorySuggestions (raw SQL)
  4. searchReadingHistory (query builder)

Test plan

  • Unit tests for processSearchQuery (normal queries, special chars, stripping, empty edge cases)
  • Integration tests for all four search endpoints with invalid tsquery input
  • Existing special character tests (c++, c#) still pass
  • Build and lint pass clean

Closes ENG-1077


Created by Huginn 🐦‍⬛

… queries

Harden processSearchQuery to strip tsquery metacharacters from user input
before constructing the query string, preventing invalid to_tsquery SQL.
Add try/catch safety net at all four search execution points (bookmark
suggestions, bookmark search, reading history suggestions, reading history
search) to catch any remaining 42601 errors and return ValidationError
instead of UNEXPECTED graphql errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@pulumi
Copy link

pulumi bot commented Mar 17, 2026

🍹 The Update (preview) for dailydotdev/api/prod (at 374cb42) was successful.

✨ Neo Explanation

This is a standard application version rollout — every service, worker, and scheduled job is being updated to run the new container image, with fresh database and ClickHouse migration jobs created to handle any schema changes in the new release.

Root Cause Analysis

A new version of the API application has been built and is being deployed. All services are being updated from the previous build to the new build, with database and ClickHouse migration jobs being replaced to run against the new version.

Dependency Chain

The new application image cascades across the entire fleet:

  • 7 Deployments (API, background workers, WebSocket, Temporal, private, personalized digest, worker jobs) are all being rolled to the new container image
  • 36 CronJobs are updated to reference the new image so future scheduled runs use the new code
  • 2 one-off migration Jobs (database and ClickHouse) from the previous deployment are deleted, and 2 new ones are created for the new version — these run schema/data migrations before or alongside the rollout

Risk analysis

No stateful resources (databases, storage buckets, persistent volumes) are being replaced or deleted. The migration Jobs are ephemeral by design and are being cleanly replaced. Kubernetes Deployments will perform rolling updates, maintaining availability throughout. The GCP credentials warning is a diagnostic-only issue with the Pulumi preview environment and does not affect the deployment itself.

Resource Changes

    Name                                                       Type                           Operation
~   vpc-native-clean-zombie-images-cron                        kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-user-companies-cron                kubernetes:batch/v1:CronJob    update
~   vpc-native-user-profile-analytics-history-clickhouse-cron  kubernetes:batch/v1:CronJob    update
~   vpc-native-calculate-top-readers-cron                      kubernetes:batch/v1:CronJob    update
~   vpc-native-check-analytics-report-cron                     kubernetes:batch/v1:CronJob    update
~   vpc-native-personalized-digest-deployment                  kubernetes:apps/v1:Deployment  update
~   vpc-native-deployment                                      kubernetes:apps/v1:Deployment  update
~   vpc-native-update-tags-str-cron                            kubernetes:batch/v1:CronJob    update
~   vpc-native-update-views-cron                               kubernetes:batch/v1:CronJob    update
~   vpc-native-validate-active-users-cron                      kubernetes:batch/v1:CronJob    update
~   vpc-native-update-source-tag-view-cron                     kubernetes:batch/v1:CronJob    update
~   vpc-native-daily-digest-cron                               kubernetes:batch/v1:CronJob    update
~   vpc-native-user-profile-analytics-clickhouse-cron          kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-gifted-plus-cron                          kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-stale-user-transactions-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-generic-referral-reminder-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-update-achievement-rarity-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-update-tag-recommendations-cron                 kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-expired-better-auth-sessions-cron         kubernetes:batch/v1:CronJob    update
~   vpc-native-rotate-weekly-quests-cron                       kubernetes:batch/v1:CronJob    update
-   vpc-native-api-clickhouse-migration-c99273ff               kubernetes:batch/v1:Job        delete
~   vpc-native-update-source-public-threshold-cron             kubernetes:batch/v1:CronJob    update
~   vpc-native-squad-posts-analytics-refresh-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-private-deployment                              kubernetes:apps/v1:Deployment  update
~   vpc-native-sync-subscription-with-cio-cron                 kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-opportunities-cron                 kubernetes:batch/v1:CronJob    update
-   vpc-native-api-db-migration-c99273ff                       kubernetes:batch/v1:Job        delete
~   vpc-native-bg-deployment                                   kubernetes:apps/v1:Deployment  update
+   vpc-native-api-clickhouse-migration-d96d54d3               kubernetes:batch/v1:Job        create
~   vpc-native-agents-digest-cron                              kubernetes:batch/v1:CronJob    update
~   vpc-native-temporal-deployment                             kubernetes:apps/v1:Deployment  update
~   vpc-native-rotate-daily-quests-cron                        kubernetes:batch/v1:CronJob    update
~   vpc-native-post-analytics-history-day-clickhouse-cron      kubernetes:batch/v1:CronJob    update
~   vpc-native-update-highlighted-views-cron                   kubernetes:batch/v1:CronJob    update
~   vpc-native-user-posts-analytics-refresh-cron               kubernetes:batch/v1:CronJob    update
~   vpc-native-personalized-digest-cron                        kubernetes:batch/v1:CronJob    update
~   vpc-native-ws-deployment                                   kubernetes:apps/v1:Deployment  update
~   vpc-native-user-profile-updated-sync-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-users-cron                         kubernetes:batch/v1:CronJob    update
+   vpc-native-api-db-migration-d96d54d3                       kubernetes:batch/v1:Job        create
~   vpc-native-expire-super-agent-trial-cron                   kubernetes:batch/v1:CronJob    update
... and 8 other changes

Move the tsquery metacharacter strip and empty check before the branching
logic so both paths share a single validation step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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