From 44cae623240e3e1f44aca1519fabe56c81652181 Mon Sep 17 00:00:00 2001 From: Alex Hawkins Date: Wed, 22 Jul 2026 18:26:48 -0700 Subject: [PATCH] fix(pglite): guard putPage against zero-row RETURNING (#1649) PGLite can return zero rows from INSERT ... ON CONFLICT DO UPDATE ... RETURNING in no-op/trigger edge cases. The previous code called rowToPage(rows[0]) unconditionally, so rows[0] was undefined and rowToPage threw "undefined is not an object (evaluating 'row.deleted_at')", which aborted the import and silently skipped the file during sync. getPage() already has the empty-rows guard; putPage() was missing the parallel one. The row was in fact written by the upsert, so re-read it via getPage() instead of crashing. On a real monorepo index this recovered ~19% of files (985/5148) that were failing to embed. Co-authored-by: Claude Opus 4.8 (1M context) Co-authored-by: Time Attakc <89218912+time-attack@users.noreply.github.com> --- src/core/pglite-engine.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/pglite-engine.ts b/src/core/pglite-engine.ts index 229322764..f74e4e964 100644 --- a/src/core/pglite-engine.ts +++ b/src/core/pglite-engine.ts @@ -1060,6 +1060,16 @@ export class PGLiteEngine implements BrainEngine { RETURNING id, source_id, slug, type, title, compiled_truth, timeline, frontmatter, content_hash, created_at, updated_at, effective_date, effective_date_source, import_filename, source_kind, source_uri, ingested_via, ingested_at`, [sourceId, slug, page.type, pageKind, page.title, page.compiled_truth, page.timeline || '', JSON.stringify(frontmatter), hash, effectiveDate, effectiveDateSource, importFilename, chunkerVersion, sourcePath, sourceKind, sourceUri, ingestedVia, ingestedAt] ); + // PGLite can return zero rows from INSERT ... ON CONFLICT DO UPDATE ... + // RETURNING in no-op/trigger edge cases, which made rowToPage(undefined) + // throw "undefined is not an object (evaluating 'row.deleted_at')" and + // skip the file during sync. The row WAS written, so re-read instead of + // crashing. + if (rows.length === 0) { + const reread = await this.getPage(slug, { sourceId }); + if (reread) return reread; + throw new Error(`putPage: RETURNING produced no row for ${sourceId}/${slug}`); + } return rowToPage(rows[0] as Record); }