{"record":{"id":"b4218ce4f55eb07e","repo":"golang-migrate/migrate","slug":"conn-v-db-v-b4218c","errorCode":null,"errorMessage":"conn: %v, db: %v","messagePattern":"conn: (.+?), db: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"database/redshift/redshift.go","lineNumber":122,"sourceCode":"\n\tmigrationsTable := purl.Query().Get(\"x-migrations-table\")\n\n\tpx, err := WithInstance(db, &Config{\n\t\tDatabaseName:    purl.Path,\n\t\tMigrationsTable: migrationsTable,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn px, nil\n}\n\nfunc (p *Redshift) Close() error {\n\tconnErr := p.conn.Close()\n\tdbErr := p.db.Close()\n\tif connErr != nil || dbErr != nil {\n\t\treturn fmt.Errorf(\"conn: %v, db: %v\", connErr, dbErr)\n\t}\n\treturn nil\n}\n\n// Redshift does not support advisory lock functions: https://docs.aws.amazon.com/redshift/latest/dg/c_unsupported-postgresql-functions.html\nfunc (p *Redshift) Lock() error {\n\tif !p.isLocked.CompareAndSwap(false, true) {\n\t\treturn database.ErrLocked\n\t}\n\treturn nil\n}\n\nfunc (p *Redshift) Unlock() error {\n\tif !p.isLocked.CompareAndSwap(true, false) {\n\t\treturn database.ErrNotLocked\n\t}\n\treturn nil\n}","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/database/redshift/redshift.go#L104-L140","documentation":"Close() on the Redshift driver closes both the raw connection and the database handle, then reports any failures combined as 'conn: %v, db: %v' (with <nil> for the healthy side). Redshift does not support postgres advisory locks, so cleanup correctness relies solely on these close calls; a failure here means connections may linger until the server times them out.","triggerScenarios":"Calling Driver.Close() after the Redshift connection was already terminated (idle timeout, admin intervention, network interruption) or when the *sql.DB was closed by the caller first.","commonSituations":"Long-running migration workers whose connections are reaped by Redshift's connection limits; Lambda/short-lived jobs where the caller's deferred close of *sql.DB runs before the driver's Close; network blips to the Redshift endpoint.","solutions":["Read both parts of the combined message; ignore 'sql: database is closed' if your code intentionally closed the *sql.DB first","Ensure only one owner closes shared handles (pass the *sql.DB to the driver and let Close() own cleanup)","Check VPC/security-group connectivity and Redshift's connection limits if closes consistently fail"],"exampleFix":"// before\ndb, _ := sql.Open(...)\nd, _ := redshift.WithInstance(instance, cfg)\ndefer db.Close() // closes handle the driver also closes\n// after\nd, _ := redshift.WithInstance(instance, cfg)\ndefer func() {\n    if err := d.Close(); err != nil {\n        log.Printf(\"migrator close: %v\", err)\n    }\n}() // single close owner","handlingStrategy":"try-catch","validationCode":"if redshiftConn.conn == nil || redshiftConn.db == nil {\n    return errors.New(\"redshift migrator already closed or not initialized\")\n}","typeGuard":null,"tryCatchPattern":"if err := driver.Close(); err != nil {\n    if strings.Contains(err.Error(), \"sql: database is closed\") {\n        return nil // intentional prior close\n    }\n    return fmt.Errorf(\"closing redshift migrator: %w\", err)\n}","preventionTips":["Let the migrator own the *sql.DB; do not close the same handle twice","Use sync.Once around Close in long-lived workers","Monitor Redshift connection limits/timeouts that reap idle connections"],"tags":["redshift","resource-cleanup","connection-close"],"backgroundTag":"connection-close-error","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}