From 216654584949dd50ec104fd996ff837fdc3358f9 Mon Sep 17 00:00:00 2001 From: Time Attakc <89218912+time-attack@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:20:10 -0700 Subject: [PATCH] =?UTF-8?q?fix(pglite):=20platform-gate=20the=20init-failu?= =?UTF-8?q?re=20banner=20=E2=80=94=20stop=20blaming=20the=20macOS=2026.3?= =?UTF-8?q?=20bug=20on=20every=20platform=20(#2674)=20(#2891)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit classifyPgliteInitError() routes bare Emscripten aborts to the 'unknown' verdict, whose hint unconditionally printed "Most common cause: the macOS 26.3 WASM bug (#223)" — even on Windows and Linux (#2195, #1870). - buildPgliteInitErrorMessage now takes a platform param (default process.platform): darwin keeps the #223 link as a *possible* cause; other platforms get the plausible off-macOS causes (lock contention, damaged data dir) plus `gbrain doctor` / `gbrain reinit-pglite`. - New stringifyPgliteInitError(): non-Error rejections (Emscripten aborts can throw plain objects) no longer print "[object Object]". - Regression tests for both branches + the stringifier in test/pglite-init-classifier.test.ts. Canonical for a 7-report class: #2674, #1870, #1195, #1502, #2195, #939, #391. Co-authored-by: Sinabina Co-authored-by: Claude Fable 5 --- src/core/pglite-engine.ts | 29 +++++++++++++++------ test/pglite-init-classifier.test.ts | 39 +++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/core/pglite-engine.ts b/src/core/pglite-engine.ts index c5bf8f1f6..2f20766b3 100644 --- a/src/core/pglite-engine.ts +++ b/src/core/pglite-engine.ts @@ -150,8 +150,8 @@ export function computeSnapshotSchemaHash( * `macos-26-3` — the pre-existing #223 hint signature (early macOS * 26.3 builds shipped a broken WASM runtime). * - * `unknown` — falls through to a generic hint that still names the - * doctor command and the most-common-cause link. + * `unknown` — falls through to a generic hint that names the doctor + * command; the macOS 26.3 link is offered only on darwin (#2674). * * Regex tightened per Codex eng-review finding #9: don't match * generic `pglite.data` substring (could fire on unrelated PGLite @@ -160,6 +160,12 @@ export function computeSnapshotSchemaHash( */ export type PgliteInitFailure = 'bunfs' | 'macos-26-3' | 'corrupt' | 'unknown'; +// #2674: non-Error rejections (Emscripten aborts can throw plain objects) +// used to stringify as "[object Object]" — prefer .message when present. +export function stringifyPgliteInitError(err: unknown): string { + return String((err as { message?: unknown })?.message ?? err); +} + export function classifyPgliteInitError(message: string): PgliteInitFailure { if (/\$\$bunfs|ENOENT[\s\S]*pglite\.data/i.test(message)) return 'bunfs'; // #2348: a corrupted PGLite data dir (two OS processes opened it concurrently @@ -179,6 +185,9 @@ export function classifyPgliteInitError(message: string): PgliteInitFailure { export function buildPgliteInitErrorMessage( verdict: PgliteInitFailure, original: string, + // #2674: threaded (defaulted) so tests can exercise both branches without + // monkey-patching process.platform. + platform: NodeJS.Platform = process.platform, ): string { const header = 'PGLite failed to initialize its WASM runtime.'; let hint: string; @@ -210,10 +219,16 @@ export function buildPgliteInitErrorMessage( break; case 'unknown': default: - hint = - ' Most common cause: the macOS 26.3 WASM bug\n' + - ' (https://github.com/garrytan/gbrain/issues/223).\n' + - ' Run `gbrain doctor` for a full diagnosis.'; + // #2674: only blame the macOS 26.3 WASM bug on macOS. On other + // platforms, point at the causes that are actually plausible there. + hint = platform === 'darwin' + ? ' Possible cause: the macOS 26.3 WASM bug\n' + + ' (https://github.com/garrytan/gbrain/issues/223).\n' + + ' Run `gbrain doctor` for a full diagnosis.' + : ' Possible causes: another gbrain process holding the database\n' + + ' (lock contention), or a damaged PGLite data directory.\n' + + ' Run `gbrain doctor` for a full diagnosis; if the data dir is\n' + + ' damaged, `gbrain reinit-pglite` rebuilds it from your brain repo.'; break; } return `${header}\n${hint}\n Original error: ${original}`; @@ -309,7 +324,7 @@ export class PGLiteEngine implements BrainEngine { // read-only on older macOS + Bun 1.3.x, so PGLite can't extract its // pglite.data WASM payload). Route the hint by failure shape so // users get the right next step. - const original = err instanceof Error ? err.message : String(err); + const original = stringifyPgliteInitError(err); // #2674 const verdict = classifyPgliteInitError(original); const wrapped = new Error(buildPgliteInitErrorMessage(verdict, original)); // Release the lock so a fresh process can try again; leaking the lock diff --git a/test/pglite-init-classifier.test.ts b/test/pglite-init-classifier.test.ts index a565332ff..d3259af95 100644 --- a/test/pglite-init-classifier.test.ts +++ b/test/pglite-init-classifier.test.ts @@ -17,6 +17,7 @@ import { describe, test, expect } from 'bun:test'; import { classifyPgliteInitError, buildPgliteInitErrorMessage, + stringifyPgliteInitError, } from '../src/core/pglite-engine.ts'; describe('classifyPgliteInitError', () => { @@ -89,13 +90,27 @@ describe('buildPgliteInitErrorMessage — hint routing', () => { expect(msg).not.toContain('Bun vfs'); }); - test('unknown verdict surfaces the doctor + #223 fallback AND original error', () => { - const msg = buildPgliteInitErrorMessage('unknown', original); + // #2674: the unknown-verdict hint is platform-gated. The macOS 26.3 + // attribution (#223) only appears on darwin; elsewhere the hint names + // the causes that are actually plausible off-macOS. + test('unknown verdict on darwin surfaces the doctor + #223 fallback AND original error', () => { + const msg = buildPgliteInitErrorMessage('unknown', original, 'darwin'); expect(msg).toContain('gbrain doctor'); expect(msg).toContain('issues/223'); expect(msg).toContain(original); }); + test('unknown verdict on non-darwin does NOT mention macOS 26.3', () => { + for (const platform of ['linux', 'win32'] as const) { + const msg = buildPgliteInitErrorMessage('unknown', original, platform); + expect(msg).not.toContain('macOS 26.3'); + expect(msg).not.toContain('issues/223'); + expect(msg).toContain('gbrain doctor'); + expect(msg).toContain('gbrain reinit-pglite'); + expect(msg).toContain(original); + } + }); + test('corrupt verdict surfaces the reinit-pglite recovery, NOT the macOS hint', () => { const msg = buildPgliteInitErrorMessage('corrupt', original); expect(msg).toContain('gbrain reinit-pglite'); @@ -112,6 +127,26 @@ describe('buildPgliteInitErrorMessage — hint routing', () => { }); }); +describe('stringifyPgliteInitError — non-Error rejections (#2674)', () => { + test('Error instance yields its message', () => { + expect(stringifyPgliteInitError(new Error('boom'))).toBe('boom'); + }); + + test('plain object with message yields the message, not "[object Object]"', () => { + const emscriptenAbort = { message: 'Aborted(). Build with -sASSERTIONS for more info.' }; + expect(stringifyPgliteInitError(emscriptenAbort)).toBe( + 'Aborted(). Build with -sASSERTIONS for more info.', + ); + }); + + test('primitive rejections stringify as-is', () => { + expect(stringifyPgliteInitError('raw string')).toBe('raw string'); + expect(stringifyPgliteInitError(42)).toBe('42'); + expect(stringifyPgliteInitError(null)).toBe('null'); + expect(stringifyPgliteInitError(undefined)).toBe('undefined'); + }); +}); + describe('#1340 reproducer — exact reporter error string maps to bunfs', () => { // This is the literal error string from the issue body. const reportError = `ENOENT: no such file or directory, open '/$$bunfs/root/pglite.data'.`;