Skip to content

pg-cloudflare: CloudflareSocket.end() throws null.close() when releasing a client whose socket already closed #3689

Description

@hkirste

Summary

CloudflareSocket.end() calls this._cfSocket!.close() with no null guard, but _addClosedHandler() sets this._cfSocket = null as soon as the underlying socket closes. When a Pool releases a client whose backend socket was already severed (e.g. an idle connection closed by a proxy such as Cloudflare Hyperdrive, or a Postgres restart, mid-request), poolClient.end()CloudflareSocket.destroy()end() dereferences null.close() and throws synchronously, crashing the in-flight request — after its transaction has already committed.

Present on master (the ! non-null assertion in end() is unsound once _cfSocket is nulled) and in published 1.3.0 / 1.4.0.

Stack trace (from production, Cloudflare Workers + Hyperdrive + drizzle)

TypeError: Cannot read properties of null (reading 'close')
at CloudflareSocket.write
at CloudflareSocket.end // this._cfSocket!.close()
at CloudflareSocket.destroy
at Client.end
at BoundPool._remove
at BoundPool._release
at Client.release // releasing the client after the txn

The transaction succeeded; only the cleanup (client release → socket teardown) throws, so the request 500s even though the work committed.

Relevant source (packages/pg-cloudflare/src/index.ts)

end(data=Buffer.alloc(0),encoding='utf8',callback=()=>{}){this.write(data,encoding,(err)=>{this._cfSocket!.close()// <-- _cfSocket may be null hereif(callback)callback(err)})returnthis}_addClosedHandler(){this._cfSocket!.closed.then(()=>{if(!this._upgrading){this._cfSocket=null// <-- nulled on closethis.emit('close')} ...
})}

Proposed fix

Guard the teardown: this._cfSocket?.close(). If the socket is already closed there is nothing to close, and end()/destroy() should be a safe no-op rather than throw. Happy to send a PR.

Workaround

Patching end() to use optional chaining (this._cfSocket?.close()) via a package patch resolves it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions