Skip to content

Query errors get a read-only stack on Node 22+ #1227

Closed

Description

@rpinckne

queryError in src/connection.js (3.4.9; the same code is on master) appends the query origin like this:

Object.defineProperties(err, {
  stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug },
  // ...
})

Since Node 22, stack on an Error instance is an own accessor property. Redefining it with only value turns it into a data property, and writable defaults to false. As a result every query error ends up with a read-only stack. Strict-mode code that rewrites the stack then throws, and error-normalizing frameworks do rewrite it.

Repro (Node 22.23, 24.0, 24.21)

'use strict'
const e = new Error('x')
Object.defineProperties(e, { stack: { value: e.stack } })
e.stack = 'y' // TypeError: Cannot assign to read only property 'stack' of object 'Error: x'

With postgres.js:

'use strict'
const err = await sql`select 1/0`.catch(e => e)
err.stack = 'y' // same TypeError

Suggested fix

stack: { value: /* ... */, enumerable: options.debug, writable: true, configurable: true },

This restores the attributes the property had before Node 22.

Impact

The Vercel Workflow step executor rewrites a thrown error's stack before it records a retry. That assignment threw inside its catch block, so a transient database error left the step running until its lease expired, instead of retrying it.

Activity

  1. rpinckne commented on Oct 13, 2026

    @rpinckne
    Author

    An update for anyone who hits this through Vercel Workflow: @workflow/core 5.0.1 and later handle a read-only stack (vercel/workflow#4549), so Workflow steps that fail on a query error retry normally again. The postgres.js behaviour described above is unchanged in 3.4.9, so the suggested fix still applies to other code that rewrites the stack.

  2. added a commit that references this issue on Oct 29, 2026
    06cf284
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions