fix(connectors): treat a zero-byte source file as nothing to index - #6848
Conversation
Observed in production after connectors began delivering source files: a zero-byte PDF was stored and shipped to OCR, which answered `400 Bad Request`. That bills an external call to discover the file was empty and reports it as an API fault rather than as what it is. Before source files existed, an empty file produced empty extracted text and was dropped at the empty-content check, so this was a regression. The emptiness rule now lives in one place, `hasIndexablePayload`, used by the sync engine's classify and hydrate gates and by both connectors' `getDocument`. It previously existed twice — the connectors asked whether a source file was present while the sync engine asked the same question a second way — and a source file with no bytes satisfied both.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview
Tests cover bytes, text, blank text, and the zero-byte rejection case. Reviewed by Cursor Bugbot for commit eabfba7. Configure here. |
Greptile SummaryThis PR centralizes connector payload eligibility in
Confidence Score: 5/5The PR appears safe to merge, with zero-byte source files consistently rejected before indexing and no actionable regression identified. The changed connector and sync-engine gates share one predicate, current producers satisfy its source-file-versus-text assumptions, and existing indexed documents remain preserved when a refreshed payload is empty.
|
| Filename | Overview |
|---|---|
| apps/sim/connectors/utils.ts | Introduces the shared payload predicate that rejects zero-byte source files and blank extracted content. |
| apps/sim/connectors/onedrive/onedrive.ts | Applies the shared predicate before returning hydrated OneDrive documents. |
| apps/sim/connectors/sharepoint/sharepoint.ts | Applies the shared predicate before returning hydrated SharePoint documents. |
| apps/sim/lib/knowledge/connectors/sync-engine.ts | Reuses the centralized payload rule at classification and hydration gates while retaining existing documents as last-known-good when refreshes are empty. |
| apps/sim/connectors/utils.test.ts | Adds focused tests for valid source bytes, extracted text, blank text, and zero-byte source files. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Connector document] --> B{Source file present?}
B -->|Yes| C{Contains bytes?}
B -->|No| D{Nonblank extracted text?}
C -->|Yes| E[Index payload]
C -->|No| F[Drop empty document]
D -->|Yes| E
D -->|No| F
Reviews (1): Last reviewed commit: "fix(connectors): treat a zero-byte sourc..." | Re-trigger Greptile
Summary
hasIndexablePayload, shared by the sync engine's classify and hydrate gates and both connectors'getDocumentWhy
Found by auditing production after connectors began delivering source files. A zero-byte PDF was stored and sent to OCR, which answered
400 Bad Request:Two problems in one. It bills an external API call to discover the file was empty, and it reports the result as a provider fault rather than as an empty file, so the row gives no one a reason they can act on.
This was a regression. Before source files existed, an empty file produced empty extracted text and was dropped at the empty-content check.
The rule also existed in two places that disagreed: the connectors asked whether a source file was present, the sync engine asked the same question a second way, and a source file with no bytes satisfied both. One definition now, so the two gates cannot drift.
Scope
This is the only unexplained failure class in the fleet since the source-file change deployed. Everything else post-deploy is legitimate and correctly reported: image-only decks, password-protected workbooks, files over the 100MB cap, and archives caught by the decompression guard.
Testing
vitest run connectors/ lib/knowledge/ lib/uploads/ lib/file-parsers/ app/api/knowledge/— 2,007 passed (129 files)bun run check:audits— 29/29tsgo --noEmit— no errors in changed files (pre-existingmssqland@c15t/nextjsresolution errors unrelated)Checklist