{"record":{"id":"971c60aee1b56f67","repo":"go-sql-driver/mysql","slug":"invalid-connection","errorCode":null,"errorMessage":"invalid connection","messagePattern":"invalid connection","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"errors.go","lineNumber":20,"sourceCode":"//\n// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\n// Various errors the driver might return. Can change between driver versions.\nvar (\n\tErrInvalidConn       = errors.New(\"invalid connection\")\n\tErrMalformPkt        = errors.New(\"malformed packet\")\n\tErrNoTLS             = errors.New(\"TLS requested but server does not support TLS\")\n\tErrCleartextPassword = errors.New(\"this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN\")\n\tErrNativePassword    = errors.New(\"this user requires mysql native password authentication\")\n\tErrOldPassword       = errors.New(\"this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords\")\n\tErrUnknownPlugin     = errors.New(\"this authentication plugin is not supported\")\n\tErrOldProtocol       = errors.New(\"MySQL server does not support required protocol 41+\")\n\tErrPktSync           = errors.New(\"commands out of sync. You can't run this command now\")\n\tErrPktSyncMul        = errors.New(\"commands out of sync. Did you run multiple statements at once?\")\n\tErrPktTooLarge       = errors.New(\"packet for query is too large. Try adjusting the `Config.MaxAllowedPacket`\")\n\tErrBusyBuffer        = errors.New(\"busy buffer\")\n\n\t// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.\n\t// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn\n\t// to trigger a resend. Use mc.markBadConn(err) to do this.\n\t// See https://github.com/go-sql-driver/mysql/pull/302\n\terrBadConnNoWrite = errors.New(\"bad connection\")\n)","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/errors.go#L2-L38","documentation":"ErrInvalidConn is the catch-all sentinel returned when the underlying connection is no longer usable. readPacket (packets.go:59,101) returns it after any I/O read failure, mc.error() (connection.go:202) returns it for a closed connection, and mysqlTx.Commit/Rollback (transaction.go:17,33,38) return it when the conn is already nil/closed. Unlike driver.ErrBadConn, this value surfaces all the way to the caller, so database/sql will NOT transparently retry it.","triggerScenarios":"Returned by tx.Commit()/tx.Rollback() when the transaction's connection was already closed or committed once; by any query/exec/ping when a network read fails mid-exchange (server killed, TCP reset, ReadTimeout elapsed); by mc.error() when an operation runs against a connection whose closed flag is set.","commonSituations":"Calling tx.Commit() twice or using a tx after the connection died; idle pooled connections killed by the server's wait_timeout; network blips; a previous statement that desynced the connection and forced a close.","solutions":["Treat ErrInvalidConn as fatal for that transaction/connection: discard both and retry the whole unit of work on a fresh connection from the pool.","Enable connection liveness checks (CheckConnLiveness=true, the default) and set ConnMaxLifetime shorter than the server's wait_timeout so stale conns are reaped before use.","Avoid reusing a *sql.Tx or *sql.Conn after any error; immediately discard it.","Increase server wait_timeout / set TCP keepalives so idle connections are not dropped."],"exampleFix":"// before: reuse tx after error, then Commit fails with ErrInvalidConn\ntx, _ := db.Begin()\nif _, err := tx.Exec(...); err != nil {\n    log.Print(err) // tx is now invalid\n}\ntx.Commit() // -> ErrInvalidConn\n\n// after: roll back and abandon tx on any error\ntx, _ := db.Begin()\nif _, err := tx.Exec(...); err != nil {\n    tx.Rollback()\n    return err\n}\nreturn tx.Commit()","handlingStrategy":"retry","validationCode":"// Before starting a unit of work, confirm the pool is reachable.\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"db unreachable: %w\", err)\n}","typeGuard":"func isInvalidConn(err error) bool {\n    return errors.Is(err, mysql.ErrInvalidConn)\n}","tryCatchPattern":"err := tx.Commit()\nif errors.Is(err, mysql.ErrInvalidConn) {\n    // conn is dead and the op did not complete; the whole tx must be\n    // retried on a fresh connection. Do NOT reuse tx or the conn.\n    return retryWholeUnit()\n}","preventionTips":["Set db.SetConnMaxLifetime() below the server's wait_timeout so dead conns are reaped first.","Keep CheckConnLiveness=true (default) so the pool checks conns before handing them out.","Never reuse a *sql.Tx or *sql.Conn after any error from it.","Always pair Begin() with a Commit() or Rollback(); defer a Rollback() right after Begin()."],"tags":["connection","network","lifecycle"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}