[Notion connector] query_data_sources SQL returns query-shape-dependent stale row snapshots
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using?
ChatGPT/Codex Desktop: 26.831.21537 (build 7579)
Embedded Codex runtime: 0.152.1
What subscription do you have?
Not disclosed. The connected Notion workspace reports that fetch, query_data_sources, view queries, and update operations are available.
What platform are you using?
macOS 26.6.2 (build 25G83)
Apple Silicon / arm64
What issue are you seeing?
The Notion connector's query_data_sources SQL mode can return different versions of the same database row depending on the SQL query shape.
A private Notion database contains one canonical row whose live page property and page body both say Approved. The database's normal view also returns Approved, and its filtered Draft view excludes the row.
However, SQL initially returned an older Draft snapshot of the same page ID, including older text and relation values.
After re-saving the live Status property as Approved and waiting for propagation:
- a targeted SQL query by unique ID returned the current
Approvedrow; - the original targeted query also eventually returned the current row;
WHERE Status = 'Approved' AND <unique ID>returned the row;WHERE Status = 'Draft'correctly excluded the row;- but a broad SQL scan still returned the same row as the older
Draftsnapshot; - SQL aggregate queries still counted the stale snapshot.
This is query-shape dependent within the same data source and observation window.
Reproduction outline
- Connect the official Notion app in Codex Desktop.
- Fetch a private Notion database and obtain its
collection://...data-source URL. - Choose one row that was previously
Draftand is nowApproved. - Confirm through
notion_fetchthat the page property isApproved. - Confirm through view-mode
query_data_sourcesthat the normal view returnsApprovedand the Draft-filtered view excludes the row. - Run equivalent SQL queries against the same data source.
Sanitized query examples:
SELECT *
FROM "collection://REDACTED"
WHERE "Record ID" = ? OR "Title" = ?;
SELECT url, "Record ID", "Title", "Status"
FROM "collection://REDACTED"
WHERE "Status" = ? AND "Record ID" = ?;
-- params: ["Approved", 26]
SELECT url, "Record ID", "Title", "Status"
FROM "collection://REDACTED"
ORDER BY "Record ID";
SELECT "Status", COUNT(*) AS row_count
FROM "collection://REDACTED"
GROUP BY "Status";
Actual result
For the same canonical page ID:
| Read path | Result |
|---|---|
| Direct page fetch | Approved, current content/relations |
| Database view mode | Approved, current content/relations |
| Draft-filtered view | Row absent |
| Targeted SQL by ID | Approved, current content/relations |
SQL WHERE Status='Approved' AND ID=? |
Row present as Approved |
SQL WHERE Status='Draft' |
Row absent |
| Broad unfiltered SQL scan | Same row appears as older Draft snapshot |
| SQL aggregate | 56 Approved / 7 Draft / 2 In Review |
| View-mode rows, counted client-side | 57 Approved / 6 Draft / 2 In Review |
The broad SQL snapshot also contained older non-status field values, so this is not only a status-filter anomaly.
The database has 65 active rows. Duplicate checks found one active record with this ID/title, no archived duplicate, one data source, and one stable page ID across all reads.
Expected behavior
All SQL query shapes over one Notion data source should resolve a canonical page ID to the same current property values.
At minimum:
- targeted, filtered, broad-scan, and aggregate SQL queries must use the same snapshot/version;
- a row excluded by
WHERE Status='Draft'must not simultaneously contribute to the Draft aggregate; - view-mode and SQL-mode reads should converge after a successful property update;
- if results are intentionally cached, the response should expose freshness/snapshot metadata and use consistent invalidation across query shapes.
Impact
Automated governance and assessment workflows can misclassify approved records, produce incorrect catalogue totals, and make decisions from stale text or relations even though direct page reads and database views are current.
Because the response has no freshness or projection version metadata, an agent cannot reliably detect which SQL shape is stale without cross-checking every row through another API path.
Additional information
Observed on 2026-09-04.
One idempotent property write was attempted to refresh the projection. It improved some targeted SQL reads after a short propagation interval but did not repair broad scans or aggregates. No repeated toggling or destructive workaround was attempted.
Temporary safe workaround: use direct page fetches or view-mode database queries for governance-critical reads and compute totals from returned view rows.
Potentially related but not a duplicate: #34618 concerns query_data_sources being unavailable; in this report the tool is available and executes, but SQL projections are internally inconsistent.
All workspace names, page/database/data-source IDs, page titles, URLs, relation targets, user identities, and private content have been removed from this public report.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the discrepancy with the listed direct-fetch, view-mode, targeted SQL, broad-scan, and aggregate queries against one data source. Compare the page IDs, returned values, and counts across query shapes and inspect the connector implementation that handles these read paths; done means all SQL shapes resolve the same current snapshot or expose consistent freshness metadata.
Written by the indexing model from the issue text.
Assessment
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100