Skip to content

Commit fe20013

Browse files
committed
fix(wrangler): prevent SQLite users error from being reported to Sentry
1 parent a879fe0 commit fe20013

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

.changeset/gold-donuts-leave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
fix: prevent reporting SQLite error from `wrangler d1 execute` to Sentry

packages/wrangler/src/__tests__/d1/execute.test.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import fs from "node:fs";
2-
import { join } from "path";
2+
import { join } from "node:path";
3+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
4+
import { UserError } from "../../errors";
35
import { mockConsoleMethods } from "../helpers/mock-console";
46
import { useMockIsTTY } from "../helpers/mock-istty";
57
import { runInTempDir } from "../helpers/run-in-tmp";
@@ -155,6 +157,31 @@ describe("execute", () => {
155157
}]
156158
`);
157159
});
160+
161+
it("should treat SQLite constraint errors as UserErrors", async () => {
162+
setIsTTY(false);
163+
writeWranglerConfig({
164+
d1_databases: [
165+
{ binding: "DATABASE", database_name: "db", database_id: "xxxx" },
166+
],
167+
});
168+
169+
// First create a table with a foreign key constraint
170+
const setupSQL = `
171+
CREATE TABLE users (id INTEGER PRIMARY KEY);
172+
CREATE TABLE posts (id INTEGER PRIMARY KEY, user_id INTEGER, FOREIGN KEY(user_id) REFERENCES users(id));
173+
`;
174+
fs.writeFileSync("setup.sql", setupSQL);
175+
await runWrangler("d1 execute db --file setup.sql --local");
176+
177+
// Now try to violate the foreign key constraint
178+
const violationSQL = `INSERT INTO posts (id, user_id) VALUES (1, 999);`;
179+
fs.writeFileSync("violation.sql", violationSQL);
180+
181+
await expect(
182+
runWrangler("d1 execute db --file violation.sql --local")
183+
).rejects.toThrow(UserError);
184+
});
158185
});
159186

160187
function useSentry() {

packages/wrangler/src/d1/execute.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,30 @@ export type QueryResult = {
4141
query?: string;
4242
};
4343

44+
// Common SQLite Codes
45+
// See https://www.sqlite.org/rescode.html#constraint
46+
const SQLITE_RESULT_CODES = [
47+
"SQLITE_ERROR",
48+
"SQLITE_CONSTRAINT",
49+
"SQLITE_MISMATCH",
50+
];
51+
52+
function isSqliteUserError(error: unknown): error is Error {
53+
if (!(error instanceof Error)) {
54+
return false;
55+
}
56+
57+
const message = error.message.toUpperCase();
58+
59+
for (const code of SQLITE_RESULT_CODES) {
60+
if (message.includes(code)) {
61+
return true;
62+
}
63+
}
64+
65+
return false;
66+
}
67+
4468
export function Options(yargs: CommonYargsArgv) {
4569
return options
4670
.Database(yargs)
@@ -305,7 +329,13 @@ async function executeLocally({
305329
try {
306330
results = await db.batch(queries.map((query) => db.prepare(query)));
307331
} catch (e: unknown) {
308-
throw (e as { cause?: unknown })?.cause ?? e;
332+
const cause = (e as { cause?: unknown })?.cause ?? e;
333+
334+
if (isSqliteUserError(cause)) {
335+
throw new UserError(cause.message);
336+
}
337+
338+
throw cause;
309339
} finally {
310340
await mf.dispose();
311341
}

0 commit comments

Comments
 (0)