From fec8c814beab3087d57c0763f404ea0288aaf1c3 Mon Sep 17 00:00:00 2001 From: Zachary LeFevre Date: Fri, 13 Mar 2026 11:31:57 -0500 Subject: [PATCH 1/3] Include extended error codes in messages --- src/workerd/util/sqlite.c++ | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/workerd/util/sqlite.c++ b/src/workerd/util/sqlite.c++ index 673cb91b9bc..84693921134 100644 --- a/src/workerd/util/sqlite.c++ +++ b/src/workerd/util/sqlite.c++ @@ -83,6 +83,93 @@ kj::String namedErrorCode(int errorCode) { #undef LITERAL } +// Maps extended error codes to their symbolic names. +// See https://www.sqlite.org/rescode.html#extended_result_code_list. +kj::Maybe namedExtendedErrorCode(int extendedErrorCode) { +#define LITERAL(name) \ + case name: \ + return kj::str(#name); + switch (extendedErrorCode) { + LITERAL(SQLITE_ABORT_ROLLBACK) + LITERAL(SQLITE_AUTH_USER) + LITERAL(SQLITE_BUSY_RECOVERY) + LITERAL(SQLITE_BUSY_SNAPSHOT) + LITERAL(SQLITE_BUSY_TIMEOUT) + LITERAL(SQLITE_CANTOPEN_CONVPATH) + LITERAL(SQLITE_CANTOPEN_DIRTYWAL) + LITERAL(SQLITE_CANTOPEN_FULLPATH) + LITERAL(SQLITE_CANTOPEN_ISDIR) + LITERAL(SQLITE_CANTOPEN_NOTEMPDIR) + LITERAL(SQLITE_CANTOPEN_SYMLINK) + LITERAL(SQLITE_CONSTRAINT_CHECK) + LITERAL(SQLITE_CONSTRAINT_COMMITHOOK) + LITERAL(SQLITE_CONSTRAINT_DATATYPE) + LITERAL(SQLITE_CONSTRAINT_FOREIGNKEY) + LITERAL(SQLITE_CONSTRAINT_FUNCTION) + LITERAL(SQLITE_CONSTRAINT_NOTNULL) + LITERAL(SQLITE_CONSTRAINT_PINNED) + LITERAL(SQLITE_CONSTRAINT_PRIMARYKEY) + LITERAL(SQLITE_CONSTRAINT_ROWID) + LITERAL(SQLITE_CONSTRAINT_TRIGGER) + LITERAL(SQLITE_CONSTRAINT_UNIQUE) + LITERAL(SQLITE_CONSTRAINT_VTAB) + LITERAL(SQLITE_CORRUPT_INDEX) + LITERAL(SQLITE_CORRUPT_SEQUENCE) + LITERAL(SQLITE_CORRUPT_VTAB) + LITERAL(SQLITE_ERROR_MISSING_COLLSEQ) + LITERAL(SQLITE_ERROR_RETRY) + LITERAL(SQLITE_ERROR_SNAPSHOT) + LITERAL(SQLITE_IOERR_ACCESS) + LITERAL(SQLITE_IOERR_AUTH) + LITERAL(SQLITE_IOERR_BEGIN_ATOMIC) + LITERAL(SQLITE_IOERR_BLOCKED) + LITERAL(SQLITE_IOERR_CHECKRESERVEDLOCK) + LITERAL(SQLITE_IOERR_CLOSE) + LITERAL(SQLITE_IOERR_COMMIT_ATOMIC) + LITERAL(SQLITE_IOERR_CONVPATH) + LITERAL(SQLITE_IOERR_CORRUPTFS) + LITERAL(SQLITE_IOERR_DATA) + LITERAL(SQLITE_IOERR_DELETE) + LITERAL(SQLITE_IOERR_DELETE_NOENT) + LITERAL(SQLITE_IOERR_DIR_CLOSE) + LITERAL(SQLITE_IOERR_DIR_FSYNC) + LITERAL(SQLITE_IOERR_FSTAT) + LITERAL(SQLITE_IOERR_FSYNC) + LITERAL(SQLITE_IOERR_GETTEMPPATH) + LITERAL(SQLITE_IOERR_LOCK) + LITERAL(SQLITE_IOERR_MMAP) + LITERAL(SQLITE_IOERR_NOMEM) + LITERAL(SQLITE_IOERR_RDLOCK) + LITERAL(SQLITE_IOERR_READ) + LITERAL(SQLITE_IOERR_ROLLBACK_ATOMIC) + LITERAL(SQLITE_IOERR_SEEK) + LITERAL(SQLITE_IOERR_SHMLOCK) + LITERAL(SQLITE_IOERR_SHMMAP) + LITERAL(SQLITE_IOERR_SHMOPEN) + LITERAL(SQLITE_IOERR_SHMSIZE) + LITERAL(SQLITE_IOERR_SHORT_READ) + LITERAL(SQLITE_IOERR_TRUNCATE) + LITERAL(SQLITE_IOERR_UNLOCK) + LITERAL(SQLITE_IOERR_VNODE) + LITERAL(SQLITE_IOERR_WRITE) + LITERAL(SQLITE_LOCKED_SHAREDCACHE) + LITERAL(SQLITE_LOCKED_VTAB) + LITERAL(SQLITE_NOTICE_RECOVER_ROLLBACK) + LITERAL(SQLITE_NOTICE_RECOVER_WAL) + LITERAL(SQLITE_OK_LOAD_PERMANENTLY) + LITERAL(SQLITE_READONLY_CANTINIT) + LITERAL(SQLITE_READONLY_CANTLOCK) + LITERAL(SQLITE_READONLY_DBMOVED) + LITERAL(SQLITE_READONLY_DIRECTORY) + LITERAL(SQLITE_READONLY_RECOVERY) + LITERAL(SQLITE_READONLY_ROLLBACK) + LITERAL(SQLITE_WARNING_AUTOINDEX) + default: + return kj::none; + } +#undef LITERAL +} + constexpr size_t RA_MAX_METRICS_QUERY_SIZE = 1024; kj::String dbErrorMessage(int errorCode, sqlite3* db) { @@ -91,6 +178,12 @@ kj::String dbErrorMessage(int errorCode, sqlite3* db) { msg = kj::strTree(kj::mv(msg), " at offset ", offset); } msg = kj::strTree(kj::mv(msg), ": ", namedErrorCode(errorCode)); + int extendedCode = sqlite3_extended_errcode(db); + if (extendedCode != errorCode) { + KJ_IF_SOME(extendedName, namedExtendedErrorCode(extendedCode)) { + msg = kj::strTree(kj::mv(msg), " (extended: ", extendedName, ")"); + } + } return msg.flatten(); } From 4a8f48fb7ba50faf29c5fca00e0d21562a3923bf Mon Sep 17 00:00:00 2001 From: Zachary LeFevre Date: Mon, 16 Mar 2026 12:26:51 -0500 Subject: [PATCH 2/3] Test extended error codes in messages --- src/workerd/util/sqlite-test.c++ | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/workerd/util/sqlite-test.c++ b/src/workerd/util/sqlite-test.c++ index c3021b4fc21..b27094e2555 100644 --- a/src/workerd/util/sqlite-test.c++ +++ b/src/workerd/util/sqlite-test.c++ @@ -1021,6 +1021,44 @@ KJ_TEST("SQLite failed statement reset") { KJ_EXPECT(db.run("SELECT COUNT(*) FROM things").getInt(0) == 4); } +KJ_TEST("SQLite extended error codes in messages") { + // Verify that error messages include named extended error codes when they differ from the + // primary error code. + auto dir = kj::newInMemoryDirectory(kj::nullClock()); + SqliteDatabase::Vfs vfs(*dir); + SqliteDatabase db(vfs, kj::Path({"foo"}), kj::WriteMode::CREATE | kj::WriteMode::MODIFY); + + db.run(R"( + CREATE TABLE things ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL + ); + )"); + + db.run("INSERT INTO things VALUES (1, 'alice')"); + + // UNIQUE/PRIMARY KEY constraint: extended code should be SQLITE_CONSTRAINT_PRIMARYKEY. + KJ_EXPECT_THROW_MESSAGE( + "(extended: SQLITE_CONSTRAINT_PRIMARYKEY)", db.run("INSERT INTO things VALUES (1, 'bob')")); + + // NOT NULL constraint: extended code should be SQLITE_CONSTRAINT_NOTNULL. + KJ_EXPECT_THROW_MESSAGE( + "(extended: SQLITE_CONSTRAINT_NOTNULL)", db.run("INSERT INTO things VALUES (2, NULL)")); + + // Errors where extended == primary should NOT have a parenthesized suffix. + // SQLITE_ERROR for "no such table" has no extended variant. + try { + db.run("SELECT * FROM nonexistent"); + KJ_FAIL_ASSERT("expected exception"); + } catch (kj::Exception& e) { + auto desc = e.getDescription(); + + KJ_EXPECT(desc.contains("SQLITE_ERROR"), desc); + // The message should NOT have a parenthesized extended code like "(SQLITE_ERROR_...)". + KJ_EXPECT(!desc.contains("(SQLITE_ERROR_"), desc); + } +} + class MockRollbackCallback { public: kj::Function create() { From f49f49be48d03ec2e9415d9ea4886693355015b9 Mon Sep 17 00:00:00 2001 From: "ask-bonk[bot]" Date: Fri, 13 Mar 2026 18:09:36 +0000 Subject: [PATCH 3/3] PR #6321: 3 issues found, review posted. Co-authored-by: zachlefevre --- .opencode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.opencode/package.json b/.opencode/package.json index 8b520c21629..93b19af4a54 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "@opencode-ai/plugin": "1.2.24" + "@opencode-ai/plugin": "1.2.26" } } \ No newline at end of file