Skip to content

v1.54.1 — Error classification: a failure now says which layer broke

Choose a tag to compare

@CarlLee1983 CarlLee1983 released this 13 Aug 13:34
· 472 commits to main since this release

Fixed

  • A dropped connection, an exhausted connection pool, an unreachable host, and a TLS failure each say so. TRANSPORT_CODES listed seven keys, so ECONNRESET, EPIPE, EHOSTUNREACH, ENETUNREACH, TLS certificate codes, PostgreSQL SQLSTATE class 08 and 53300, and MySQL 1040 all carried a code, skipped the message-pattern fallback (which only runs when there is none), and landed on Database error (ECONNRESET): … with hints about dbcli schema. They now map to four new categories — CONNECTION_LOST, TOO_MANY_CONNECTIONS, EHOSTUNREACH, TLS_ERROR — each with the remedy that actually applies: retry a transient drop, inspect pg_stat_activity / Threads_connected against max_connections, check routing and VPN rather than DNS, or point caPath / rejectUnauthorized at the right certificate. PostgreSQL class 57 (57P01 / 57P02 / 57P03) and MySQL 1053 / 2006 / 2013 join them: restarting the server under a running query was reported as Database error (57P01) with hints about confirming the statement's objects. The codeless wordings drivers use for the same event — Connection terminated unexpectedly, server closed the connection, server has gone away — are recognized too. 57P03 (still starting up) and 08004 (the server answered and refused) get their own categories rather than borrowing a message that says the opposite, and TLS is matched by code prefix because enumerating OpenSSL's verify codes would keep missing some. The envelope states each cause in its own words instead of inheriting the shared recovery code's description — CONN_HOST_NOT_FOUND says the name could not be resolved, which is the one thing EHOSTUNREACH rules out — and TLS failures no longer route to the credentials plan, whose second step re-runs init for a certificate it never asks about. The adapter-code-to-envelope-code and the connection-versus-statement tables are both exhaustive Records over the code union now, so a future code cannot silently inherit a generic category, and the REPL's reconnect decision reads the same table instead of its own list of codes and message substrings (#62).

  • insert / update / delete / q no longer report every failure as "failed to connect". All four branched on instanceof ConnectionError and applied one message key, but that class carries every adapter-level error and only four of its nine codes are transport failures — so a missing table, a syntax error, or a statement timeout all arrived as Failed to connect to database: … while the connection was fine. The wording is now chosen by code, and rendering goes through the same formatCliError the central presenter uses, so these commands print the stable Code: line and the error's hints — both previously dropped on this path — exactly as query does (#61).

  • A statement the server canceled is no longer reported as a connection failure. PostgreSQL 57014, MySQL 3024, and MariaDB 1969 fell through to UNKNOWN / CONN_UNKNOWN, so the CLI answered a query that ran out of statement time with connection-troubleshooting hints and a recovery plan that opened with dbcli doctor — the one thing that was not broken. They now map to a STATEMENT_TIMEOUT adapter code whose hints point at the query (dbcli lint, dbcli explain, re-run with an explicit --statement-timeout <ms>). The --recovery envelope keeps schemaVersion 1 and reports CONN_TIMEOUT with details.connectionCode: "STATEMENT_TIMEOUT"; that field selects the query-oriented plan, replaces the network-flavored message with one that states the ceiling that was in force, and suppresses both the doctor-* branches — whose branchFork.after: 1 assumed step 1 was doctor — and the verify step, since nothing verifies this error except re-running the statement, which only the caller has. PostgreSQL 57014 is query_canceled, not only statement_timeout, so a pg_cancel_backend() or recovery-conflict cancel keeps the verbatim Database error (57014): … form rather than asserting a ceiling nobody set.