fix(sqlite): support Node 23.0β23.10 runtimes lacking StatementSync.columns()#90035
fix(sqlite): support Node 23.0β23.10 runtimes lacking StatementSync.columns()#90035sjf wants to merge 1 commit into
Conversation
|
@clawsweeper review |
|
π¦π§Ή I asked ClawSweeper to review this item again. Re-review progress:
|
|
Codex review: needs real behavior proof before merge. Reviewed June 8, 2026, 6:00 PM ET / 22:00 UTC. Summary PR surface: Source -2, Tests +82. Total +80 across 3 files. Reproducibility: yes. from source: current main unconditionally calls Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Keep the shared executor, preserve raw row-returning SQL behavior or explicitly narrow that contract, add hidden-columns coverage for that path, then post redacted Node 23.9 proof before merge. Do we have a high-confidence way to reproduce the issue? Yes from source: current main unconditionally calls Is this the best way to solve the issue? No as-is. The shared SQLite/Kysely executor is the right layer, but the best fix must preserve raw row-returning behavior or make a maintainer-approved contract change before merge. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 6c4fb997e52e. Label changesLabel justifications:
Evidence reviewedPR surface: Source -2, Tests +82. Total +80 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
deeef96 to
a986080
Compare
364f16e to
3e3c59b
Compare
bc6b809 to
6ec319a
Compare
|
@clawsweeper review |
|
π¦π§Ή I asked ClawSweeper to review this item again. Re-review progress:
|
β¦olumns() node:sqlite added StatementSync.columns() in v22.16/v23.11, but it is absent on Node 23.0β23.10 β runtimes that still satisfy engines (>=22.19.0). The Kysely sync and driver execute paths called it unconditionally, so a post-upgrade `openclaw doctor` crashed the plugin install index and task registry/flow sidecar migrations with "statement.columns is not a function". Centralize a single executeCompiledQuerySync that feature-detects columns() and, when absent, classifies result-returning statements from the compiled query shape. Collapses the previously duplicated sync/driver execute logic into one path. Fixes #90007 Co-Authored-By: Claude Opus 4.8 <[email protected]>
6ec319a to
e4b9ba9
Compare
|
@clawsweeper review |
|
π¦π§Ή I asked ClawSweeper to review this item again. Re-review progress:
|
Summary
Fixes #90007. After upgrading to 2026.6.1, the post-update
openclaw doctorstep crashed on Node 23.0β23.10 with:across the plugin install index, task registry sidecar, and task flow sidecar migrations.
Root cause
StatementSync.prototype.columns()(node:sqlite) was Added in: v23.11.0, v22.16.0 (per the Node docs). Because Node 22 is LTS and got the backport, the timeline is non-linear:.columns()exists on 22.16+ (so all of ourengines: >=22.19.0floor), on 23.11+, and on 24+ β but not on 23.0 through 23.10. The reporter's Node 23.9.0 lands squarely in that hole, yet satisfies the declared engine, so it is a supported runtime.Both SQLite execute paths called
statement.columns()unconditionally to decide between.all()(result-returning) and.run():src/infra/kysely-sync.tsβ the sync helper used by every state migrationsrc/infra/kysely-node-sqlite.tsβ the Kysely driverexecuteQueryFix
Two changes, both centered in
src/infra/kysely-node-sqlite.ts:1. Make the
.all()-vs-.run()decision version-robust (statementReturnsRows). Feature-detect.columns(); on runtimes that have it (Node 22.16+/23.11+/24+) behavior is unchanged. When it's absent (Node 23.0β23.10), classify result-returning statements from the typed Kysely operation node β no SQL string parsing:SelectQueryNodeβ rowsInsert/Update/DeleteQueryNodeβ rows iff aRETURNINGclause is present (node.returning != null)This is exact for every query OpenClaw runs through this dialect: all callers use Kysely builders, and the dialect itself only raw-executes transaction control.
2. Coalesced the two duplicated execute paths to remove the duplication.
statementReturnsRowshas to be shared by both call sites, and the surrounding bodies were already near-identical copies (prepareβ row check βall()/run()β insert metadata). Rather than duplicate the new logic across both, the async driver'sexecuteQueryand the sync helper'sexecuteCompiledSqliteQuerySyncare now unified into a singleexecuteCompiledQuerySync, and both delegate to it. This also reconciles a pre-existing inconsistency where the two paths detected inserts differently (raw SQLstartsWith("insert")vsInsertQueryNode.is) β they now shareInsertQueryNode.is. Net result:kysely-sync.tsshrinks (its bespoke body is deleted), and the row-detection logic lives in exactly one place.Verification
Reproduced and verified against a standalone Node v23.9.0 (the reporter's runtime) and local Node v26:
columnsabsent)columnspresent)TypeError: statement.columns is not a functionExercised through both the sync helper (
executeSqliteQuerySync, the path the migrations use) and the async Kysely driver: insert +insertId, select,INSERT β¦ RETURNING, update, delete,takeFirst, transaction rollback, savepoints, and streaming β identical results on both runtimes.New regression tests simulate a
node:sqlitebuild withoutStatementSync.columns()(aProxythat hides the method), so CI on Node 24 still exercises the fallback classifier through both the sync and driver entry points.Local commands (normal source checkout):
All green (kysely infra 7, types 1, doctor-state-migrations 51, installed-plugin-index 14).
Thanks to @TreyLawrence for the precise report and reproduction.