mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(pglite): platform-gate the init-failure banner — stop blaming the macOS 26.3 bug on every platform (#2674) (#2891)
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 <sinabina@Sinabinas-MacBook-Pro-4.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Sinabina
Claude Fable 5
parent
10ad7f156a
commit
2166545849
@@ -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
|
||||
|
||||
@@ -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'.`;
|
||||
|
||||
Reference in New Issue
Block a user