Skip to content

fix: support the msnodesqlv8 5.6 error, cancel and info events - #1917

Merged
dhensby merged 5 commits into
tediousjs:masterfrom
dhensby:fix/msnodesqlv8-5.6-events
Oct 13, 2026
Merged

dhensby merged 5 commits into
tediousjs:masterfrom
dhensby:fix/msnodesqlv8-5.6-events

Conversation

@dhensby

@dhensby dhensby commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

What this does:

msnodesqlv8 5.6.0 (2026-10-11) changed how errors, cancels and info messages reach event consumers. The floating msnodesqlv8@^5 CI step turned master red the next day, in run 38225080240, with no change to our code. The failures were all 16 Windows Node 22/24 jobs, and only the msnodesqlv8 v5 step.

setup-sqlserver had no part in it. Its SHA, Native Client and SQL Server builds were the same in the green and the red run, and the tedious and msnodesqlv8@^4 steps passed in the same jobs.

The CI failures pointed at real bugs for anyone installing msnodesqlv8 today.

Each commit fixes one of them:

  1. fix: reject msnodesqlv8 requests whose errors do not end the batch
    • In 5.6 an error that does not end the batch arrives with more=true and the query carries on to 'done' (fix: prints, errors and results after a failed statement in a batch were lost TimelordUK/node-sqlserver-v8#475). The adapter only failed on a more=false error, so these requests resolved: execute() of a missing procedure, RAISERROR followed by results, and a PreparedStatement whose prepare fails.
    • Requests now reject in 'done' when errors were collected, as on tedious.
    • This commit adds stub-driven unit tests for the adapter. They stand a fake in for require('msnodesqlv8') and play the events each version emits, so this logic is tested on every CI job and locally, not just on Windows.
  2. fix: keep every preceding error on msnodesqlv8 requests: precedingErrors kept only one earlier error. Batches now report several, so all are kept, as on tedious.
  3. fix: reject a terminated msnodesqlv8 statement with its own error
  4. fix: report cancelled msnodesqlv8 requests, including paused streams, as ECANCEL
    • 5.6 can cancel a running query. It emits 'done' as soon as the cancel is through, then a late HY008 Operation canceled error.
    • The adapter took that 'done' as success. So a cancelled request resolved with partial results, and a stream emitted an EREQUEST after 'done'.
    • A cancel now reports ECANCEL. Streams get an 'error' and then 'done' with what was read, as on tedious; this also covers a paused stream on any msnodesqlv8 version.
    • Anything msnodesqlv8 emits after 'done' is ignored, but an 08S01 still marks the connection.
    • The README documents both points.
  5. ci: correct the note on msnodesqlv8 v5 prebuilds: the note claimed ^5 could never load on Node 20 again; since 5.3.0 msnodesqlv8 ships a single Node-API binary. This commit only changes the comment.
    • Node 22/24 deliberately keep floating on msnodesqlv8@^5, so CI meets each new release when users do. That is how 5.6.0 was caught.
    • An exact pin was tried and dropped in review.
    • The old event behaviour stays covered by v4, and by 5.2.1 on Node 20.

Behaviour change to note:

  • Cancelling a paused msnodesqlv8 stream used to end with a bare 'done'. On every msnodesqlv8 version it now emits 'error' (ECANCEL) first, which matches tedious and the README.
  • pipe() / toReadableStream() consumers without an error listener will now see that error, as they already do on tedious.

Known limits: these can't be fixed in the adapter and have been reported upstream in TimelordUK/node-sqlserver-v8#479.

  • On 5.6 a cancel that the driver silently refuses still reports 'done' and success, so it is reported here as ECANCEL.
  • A cancel racing a query's completion on msnodesqlv8 below 5.6 can report ECANCEL.

Testing:

  • Lint, the unit tests (159, including 21 new stub-driven msnodesqlv8 tests) and the CLI tests pass locally.
  • The tedious integration suite passes locally against Azure SQL Edge. The exception is user defined types, which always fails there because SQL Edge has no CLR.
  • The new and changed integration tests cover a non-batch-ending error, a constraint violation (2627 not 3621) and a running-query cancel. The transaction test that used to hang for 30s, and then stalled the after all hook, now fails fast.
  • The msnodesqlv8 behaviour was checked against the 2.7.0, 3.1.0, 4.5.0, 5.2.1, 5.5.x and 5.6.0 sources.
  • Windows CI is the first real run against the driver itself. Two things to watch:

Related issues:

Upstream reports for the 5.6.0 behaviour:

The other change, TimelordUK/node-sqlserver-v8#475 (an error that does not end the batch arrives with more=true, then 'done'), was not reported. It is intended and documented: the v5.6.0 release notes call it "the main thing to warn about". Commit 1 adapts to it.

Pre/Post merge checklist:

  • Update change log

🤖 Generated with Claude Code

Comment thread .github/workflows/nodejs.yml Outdated
dhensby and others added 3 commits October 12, 2026 16:36
msnodesqlv8 5.6 reports an error that does not end the batch with
more=true and carries on to 'done', where earlier versions ended the
batch on it with more=false. A request only failed on a more=false
error, so under 5.6 these requests resolved: executing a procedure that
does not exist, a RAISERROR followed by results, a prepared statement
that fails to prepare.

A request now fails in 'done' when errors were collected on the way, as
it does on tedious. Streams are unchanged: they emit each error as it
arrives.

The msnodesqlv8 driver only runs on Windows CI, so the new unit tests
stand a stub in for it and play the events each version emits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A failed msnodesqlv8 request kept only the error just before the last
one in `precedingErrors`. msnodesqlv8 5.6 carries a batch on after an
error, so a batch can now report several, and the earlier ones were
lost. Keep them all, as tedious does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a statement is terminated, SQL Server follows its error with 3621
"The statement has been terminated.". msnodesqlv8 5.6 emits that
message ahead of the error, and the request failed with the 3621
instead of the error that caused it, such as 2627 for a duplicate key.

The message now settles the request only when the error came with it in
the same diagnostics, which msnodesqlv8 2.0 needs because it can stop
after the message. Otherwise the error that follows, or 'done', settles
the request. A stream no longer emits that error a second time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A cancel-generated done can release a connection while the driver is still using it, allowing unsafe concurrent reuse.

2 open findings
What changed in this PR

Adapts the msnodesqlv8 adapter to version 5.6 event ordering and cancellation behavior.

Changes:

  • Preserves and reports batch errors correctly.
  • Reports cancellations as ECANCEL.
  • Adds event-stub and integration coverage plus documentation updates.
File Description
lib/​msnodesqlv8/​request.js Handles revised error, info, and cancellation events.
test/​common/​unit.js Adds msnodesqlv8 event-stub tests.
test/​common/​tests.js Adds shared error and cancellation integration tests.
test/​msnodesqlv8/​msnodesqlv8.js Enables version-aware msnodesqlv8 tests.
test/​tedious/​tedious.js Runs new shared tests against tedious.
README.md Documents cancellation behavior.
.github/​workflows/​nodejs.yml Corrects the prebuild compatibility note.
.github/​copilot-instructions.md Documents the event-stub testing convention.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/common/unit.js
Comment thread lib/msnodesqlv8/request.js Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The version-specific event behavior is handled consistently and covered by focused unit and integration tests.

0 open findings

2 resolved since last review

🧠 Review effort: Balanced

dhensby and others added 2 commits October 13, 2026 10:56
… as ECANCEL

msnodesqlv8 ends a cancelled query with 'done': a paused one in every
version, and from 5.6 a running one too, followed by an 'Operation
canceled' error. The request took that 'done' for success, so a
cancelled request resolved with what had been read so far, and on 5.6 a
stream went on to emit the late error after 'done'.

A cancel is now reported as ECANCEL, as on tedious: a stream emits it as
an error and then completes with what was read. The late error is
dropped, and nothing msnodesqlv8 emits after 'done' reaches the request,
though a broken link still marks the connection. Before 5.6 msnodesqlv8
refuses to cancel a running query that is not paused, which runs to
the end as it did before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The note above the msnodesqlv8 v5 steps said upstream only builds
prebuilds for Node 22, 24 and 26, so a floating `^5` could never load
on Node 20 again. From 5.3.0 msnodesqlv8 ships a single Node-API binary
instead of one per ABI, which may well load on Node 20; it has not been
tried here, so Node 20 stays on 5.2.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Native-driver event ordering, cancellation races, and version compatibility warrant final human validation on Windows CI.

0 open findings

🧠 Review effort: Balanced

@dhensby
dhensby merged commit 4d8039c into tediousjs:master Oct 13, 2026
47 checks passed
@dhensby
dhensby deleted the fix/msnodesqlv8-5.6-events branch October 13, 2026 11:00
dhensby added a commit to dhensby/node-mssql that referenced this pull request Oct 13, 2026
Leave a cancelled request to its driver when its stream is destroyed. Since tediousjs#1917 msnodesqlv8 reports a cancelled stream with an ECANCEL error after the query is gone and its connection released; resuming the request then made msnodesqlv8 read the freed statement, emitting a 'cannot call dead statement' / 'Statement not found' error and extra 'done' and 'free' events on a connection already back in the pool. tedious resumes a cancelled request itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 12.7.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants