Skip to content

fix: clear error when sql_variant used in TVP columns#1841

Merged
dhensby merged 3 commits intotediousjs:masterfrom
dhensby:fix/tvp-variant-error
Apr 17, 2026
Merged

fix: clear error when sql_variant used in TVP columns#1841
dhensby merged 3 commits intotediousjs:masterfrom
dhensby:fix/tvp-variant-error

Conversation

@dhensby
Copy link
Copy Markdown
Collaborator

@dhensby dhensby commented Apr 14, 2026

Summary

Fixes #1796.

When a TVP contains sql_variant columns, the tedious driver throws an unhelpful uncaught exception because its sql_variant type has all serialization methods (generateTypeInfo, validate, generateParameterLength, generateParameterData) stubbed with throw new Error('not implemented').

This PR:

  1. Detects sql_variant columns early in parameterCorrection() and throws a clear RequestError explaining the limitation and suggesting a more specific data type.

  2. Wraps parameter serialization in try/catch in both _query() and _execute() paths so that errors from parameterCorrection() (and any other parameter processing errors) are properly routed to the callback instead of thrown as uncaught exceptions.

  3. Adds a unit test verifying the error message.

Root cause

This is ultimately a limitation in the tedious driver — sql_variant is not implemented for parameter serialization. A full fix would require implementing sql_variant support in tedious itself, which is non-trivial as it is a container type that can hold many different SQL Server types. This PR provides a clear error message in the meantime.

Error message

Before:

RequestError: Input parameter 'Filters' could not be validated

After:

RequestError: Column 'Value1' in TVP 'dbo.GridFilter' uses sql_variant which is not supported by the tedious driver for TVP column types. Consider using a more specific data type.

@dhensby
Copy link
Copy Markdown
Collaborator Author

dhensby commented Apr 15, 2026

@Avi-E-Koenig - how does this look to you?

@Avi-E-Koenig
Copy link
Copy Markdown

@Avi-E-Koenig - how does this look to you?

hi @dhensby this could definitley clear confusion in this use case

The tedious driver does not implement serialization for sql_variant
(generateTypeInfo, validate, etc. all throw 'not implemented'). When
a TVP contains sql_variant columns, this caused an unhelpful error
during request execution.

This change:
- Detects sql_variant columns in parameterCorrection() and throws a
  clear RequestError explaining the limitation and suggesting a more
  specific data type
- Wraps parameter serialization in try/catch in both _query() and
  _execute() paths so errors from parameterCorrection() are properly
  routed to the callback instead of thrown as uncaught exceptions
- Adds a reproduction script (repro-1796.js) and unit test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves developer-facing error handling for Table-Valued Parameters (TVPs) containing sql_variant columns when using the tedious driver, preventing unhelpful uncaught exceptions and providing a clearer limitation message.

Changes:

  • Detects sql_variant TVP columns during parameter correction and throws a clearer RequestError.
  • Wraps parameter addition/serialization with try/catch in _query() and _execute() to route parameter-processing failures to the callback.
  • Adds a unit test to assert that the error message mentions sql_variant and the problematic column name.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
lib/tedious/request.js Adds early sql_variant TVP detection and wraps parameter setup in try/catch for query/execute paths.
test/common/unit.js Adds a unit test validating the improved error message for sql_variant TVP columns.
Comments suppressed due to low confidence (1)

lib/tedious/request.js:730

  • The catch here calls handleError(true, connection, error), but handleError does not delete this._cancel and (when this.stream === true) it will emit error without removing listeners / releasing the borrowed connection / invoking the callback. For errors thrown before execSql/execSqlBatch is called (e.g., from parameterCorrection()), this can leak the connection and leave a stale _cancel function pointing at a released connection. Consider handling this catch as a fatal pre-exec failure: remove the event listeners, delete this._cancel, release the connection, mark hasReturned, and surface the original error (without re-wrapping if it’s already a RequestError).
        try {
          if (!this._isBatch) {
            for (const name in this.parameters) {
              if (!objectHasProperty(this.parameters, name)) {
                continue
              }
              const param = this.parameters[name]
              if (param.io === 1) {
                req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
              } else {
                req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
              }
            }
          }

          connection[this._isBatch ? 'execSqlBatch' : 'execSql'](req)
        } catch (error) {
          handleError(true, connection, error)
        }

Comment thread lib/tedious/request.js
dhensby and others added 2 commits April 17, 2026 10:16
When a parameter validation error occurs during batch execution in
_query(), the connection was released back to the pool without removing
the infoMessage/errorMessage/error listeners and without clearing the
_cancel callback. This could cause memory leaks and cross-request event
handling on pooled connections.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply the same listener cleanup pattern to the _execute() catch block:
remove event listeners, delete _cancel, and set hasReturned before
releasing the connection. Also preserve RequestError instances thrown
by parameterCorrection() instead of double-wrapping them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dhensby dhensby merged commit e53d194 into tediousjs:master Apr 17, 2026
47 checks passed
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 12.3.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@dhensby dhensby deleted the fix/tvp-variant-error branch April 17, 2026 10:50
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.

Table-Valued Parameter validation fails during request.execute() despite matching SQL type (mssql@12.1.0)

3 participants