hcengineering/platform · error
DB client is already closed
Error message
DB client is already closed
What it means
getClient on the postgres-base connection wrapper throws this Error when the connection has already been closed (`closed === true`). After close() is called, the underlying postgres.Sql client is no longer usable, so any attempt to obtain a client is rejected. It guards against using or double-closing a shut-down DB connection.
Source
Thrown at foundations/core/packages/postgres-base/src/index.ts:166
export class ClientRef implements PostgresClientReference {
id = ++clId
constructor (
readonly client: PostgresClientReferenceImpl,
readonly mgr: ConnectionMgr
) {
clientRefs.set(this.id, this)
}
url (): string {
return this.client.url()
}
closed = false
async getClient (): Promise<postgres.Sql> {
if (!this.closed) {
return this.client.getClient()
} else {
throw Error('DB client is already closed')
}
}
close (): void {
// Do not allow double close of mongo connection client
if (!this.closed) {
clientRefs.delete(this.id)
this.closed = true
this.client.close()
}
}
}
export let dbExtraOptions: Partial<Options<any>> = {}
export function setDBExtraOptions (options: Partial<Options<any>>): void {
dbExtraOptions = options
}
View on GitHub (pinned to 63e28dc964)
Solutions
- Guard with the public `closed` property before calling getClient, and re-create the connection if it was closed
- Do not call close() until all pending operations complete; await outstanding work before teardown
- Ensure singleton connection holders are updated (set to null/recreated) after close so stale references aren't reused
- In tests, use a fresh connection per test or only close after all awaited queries finish
Example fix
// before
const client = await conn.getClient() // throws if closed
// after
if (conn.closed) {
conn = createConnection(config)
}
const client = await conn.getClient() Defensive patterns
Strategy: type-guard
Validate before calling
if (conn.closed) {
conn = recreateConnection(config)
}
const client = await conn.getClient() Type guard
function isConnectionOpen(conn: { closed: boolean }): boolean {
return !conn.closed
} Try / catch
let client: postgres.Sql
try {
client = await conn.getClient()
} catch (e) {
if (e instanceof Error && e.message === 'DB client is already closed') {
conn = recreateConnection(config)
client = await conn.getClient()
} else {
throw e
}
} Prevention
- Check the `closed` flag before reusing cached connection references
- Null out or recreate singletons after calling close()
- Await all in-flight queries before teardown/shutdown
- In tests, scope connection close to afterAll and never share closed instances
When it happens
Trigger: Calling getClient (foundations/core/packages/postgres-base/src/index.ts:166) on a connection instance after close() has been invoked on it — e.g., during shutdown handlers, hot-reload, or when a cached connection reference outlives its close call.
Common situations: Application shutdown code closing the DB while in-flight requests still call getClient; tests that close a shared connection in afterEach while other async work continues; service restart/reconnect logic holding a stale singleton; double teardown from both framework lifecycle and explicit close.
Related errors
- Hierarchy is not defined
- Model is not defined
- Container not found
- Reference not found
- adapter not provided: ${name}
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/ea8177dd7ead0a9b.
Report an issue: GitHub.