• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / storage / 31193672639

07 Aug 2026 03:38PM UTC coverage: 80.689% (+0.09%) from 80.602%
31193672639

Pull #1309

github

web-flow
Merge fda2cc23a into 6b6903971
Pull Request #1309: fix: extract postgres commons for watt

5676 of 7564 branches covered (75.04%)

Branch coverage included in aggregate %.

104 of 111 new or added lines in 9 files covered. (93.69%)

10716 of 12751 relevant lines covered (84.04%)

512.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.44
/src/internal/database/postgres/pool-errors.ts
1
import { DatabaseError, type Pool } from 'pg'
2

3
const disposeClientOnRelease = Symbol('disposeClientOnRelease')
120✔
4

5
type DisposableQueryError = Error & {
6
  [disposeClientOnRelease]?: true
7
}
8

9
export function createAbortError(): Error & { code: string } {
10
  const error = new Error('Query was aborted') as Error & { code: string }
32✔
11
  error.name = 'AbortError'
32✔
12
  error.code = 'ABORT_ERR'
32✔
13
  return error
32✔
14
}
15

16
export function shouldDisposeClient(error: unknown): boolean {
17
  return (
148✔
18
    error instanceof Error &&
432✔
19
    (error.name === 'AbortError' ||
20
      (error as DisposableQueryError)[disposeClientOnRelease] === true)
21
  )
22
}
23

24
export function markClientDisposable(error: unknown): void {
25
  if (error instanceof Error) {
9!
26
    // The pool release path reads this marker from the exact Error instance
27
    // thrown by the query. Do not wrap or replace it before releasing the client.
28
    const disposableError = error as DisposableQueryError
9✔
29
    disposableError[disposeClientOnRelease] = true
9✔
30
  }
31
}
32

33
export function isConnectionStateError(error: unknown): boolean {
34
  if (!(error instanceof Error)) {
105✔
35
    return false
1✔
36
  }
37

38
  if (error instanceof DatabaseError) {
104✔
39
    return error.code ? error.code.startsWith('08') : isPgProtocolError(error)
88✔
40
  }
41

42
  return isPgProtocolError(error)
16✔
43
}
44

45
function isPgProtocolError(error: Error): boolean {
46
  return (
18✔
47
    error.message.startsWith('received invalid response:') ||
49✔
48
    error.message.startsWith('Received unexpected ') ||
49
    error.message.startsWith('Unknown authenticationOk message type')
50
  )
51
}
52

53
// Socket-level failures of a dead pooled connection can surface as plain Errors.
54
// No setup has run yet, so a fresh client can safely retry. Connection-establishment
55
// failures such as ECONNREFUSED and connect timeouts are deliberately excluded.
56
export function isBrokenClientError(error: unknown): boolean {
57
  if (!(error instanceof Error) || error.name === 'AbortError') {
10✔
58
    return false
2✔
59
  }
60

61
  if ((error as DisposableQueryError)[disposeClientOnRelease] === true) {
8!
NEW
62
    return true
×
63
  }
64

65
  const code = (error as NodeJS.ErrnoException).code
8✔
66
  return (
8✔
67
    code === 'ECONNRESET' ||
26✔
68
    code === 'EPIPE' ||
69
    error.message === 'Connection terminated unexpectedly' ||
70
    error.message === 'Client has encountered a connection error and is not queryable'
71
  )
72
}
73

74
export function isConnectionTimeoutError(error: unknown): error is Error {
75
  return (
8✔
76
    error instanceof Error &&
31✔
77
    (error.message === 'timeout expired' ||
78
      error.message === 'timeout exceeded when trying to connect' ||
79
      error.message === 'Connection terminated due to connection timeout')
80
  )
81
}
82

83
export function isConnectionLimitError(error: unknown): boolean {
84
  // PgBouncer can report connection limits as 08P01 protocol_violation. That
85
  // intentionally overlaps isConnectionStateError so failed clients are both
86
  // retried and disposed instead of being returned to the pool.
87
  return (
11✔
88
    error instanceof DatabaseError &&
15!
89
    ((error.code === '08P01' && error.message.includes('no more connections allowed')) ||
90
      error.message.includes('Max client connections reached'))
91
  )
92
}
93

94
export function isRetryableTransactionSetupError(error: unknown): boolean {
95
  return (
19✔
96
    isConnectionStateError(error) || isConnectionLimitError(error) || isBrokenClientError(error)
40✔
97
  )
98
}
99

100
export type PoolErrorHandler = (error: Error) => void
101

102
export function attachPoolErrorHandler<T extends Pool>(pool: T, onError: PoolErrorHandler): T {
103
  pool.on('error', onError)
77✔
104
  return pool
77✔
105
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc