{"record":{"id":"c254e49811dcb5db","repo":"redis/go-redis","slug":"redis-no-initconnfunc-set-for-conn-d","errorCode":null,"errorMessage":"redis: no initConnFunc set for conn[%d]","messagePattern":"redis: no initConnFunc set for conn\\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pool/conn.go","lineNumber":709,"sourceCode":"}\n\n// SetOnCscReinit sets the client-side-caching pre-reinitialization hook,\n// overwriting any previous one.\nfunc (cn *Conn) SetOnCscReinit(fn func()) {\n\tcn.onCscReinit = fn\n}\n\n// SetInitConnFunc sets the connection initialization function to be called on reconnections.\nfunc (cn *Conn) SetInitConnFunc(fn func(context.Context, *Conn) error) {\n\tcn.initConnFunc = fn\n}\n\n// ExecuteInitConn runs the stored connection initialization function if available.\nfunc (cn *Conn) ExecuteInitConn(ctx context.Context) error {\n\tif cn.initConnFunc != nil {\n\t\treturn cn.initConnFunc(ctx, cn)\n\t}\n\treturn fmt.Errorf(\"redis: no initConnFunc set for conn[%d]\", cn.GetID())\n}\n\nfunc (cn *Conn) SetNetConn(netConn net.Conn) {\n\t// Store the new connection atomically first (lock-free)\n\tcn.setNetConn(netConn)\n\t// Protect reader reset operations to avoid data races\n\t// Use write lock since we're modifying the reader state\n\tcn.readerMu.Lock()\n\tcn.rd.Reset(netConn)\n\tcn.readerMu.Unlock()\n\n\tcn.bw.Reset(netConn)\n\n\t// A new socket is a new server session with no HIMPORT fieldsets and\n\t// nothing left to discard.\n\tcn.ClearPreparedFieldsets(0)\n}\n","sourceCodeStart":691,"sourceCodeEnd":727,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/internal/pool/conn.go#L691-L727","documentation":"pool.Conn.ExecuteInitConn runs the deferred connection-initialization function (set by the pool during dialing — AUTH, SELECT, OnConnect hooks). If called when initConnFunc was never set, it returns 'redis: no initConnFunc set for conn[%d]'. This indicates an internal lifecycle bug or out-of-order use of the pool's low-level conn API rather than a normal user error.","triggerScenarios":"Calling ExecuteInitConn on a Conn created/reused before InitConn assigned initConnFunc; custom pool extensions or tests invoking ExecuteInitConn directly on a freshly created Conn; races where a conn is executed before its init function is installed.","commonSituations":"Custom forks or wrappers around internal/pool; reconnect logic that reuses Conn structs without re-running InitConn; unit tests of pool internals.","solutions":["Only call ExecuteInitConn after pool.InitConn has run for that Conn","Check for nil / lifecycle ordering in custom code that touches internal/pool.Conn directly","If seen from stock go-redis usage, file an issue — it signals an internal race or bug","Guard callers: check that the conn was dialed/initialized before executing init"],"exampleFix":"// before\ncn := &pool.Conn{}\ncn.ExecuteInitConn(ctx) // no initConnFunc set\n// after\ncn, err := pool.Dial(ctx)\nif err == nil {\n\tcn.SetNetConn(netConn)\n\tcn.InitConn(ctx) // installs initConnFunc\n\tcn.ExecuteInitConn(ctx)\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := cn.ExecuteInitConn(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"no initConnFunc set\") {\n\t\t// conn was not initialized; re-run InitConn\n\t\tif ierr := cn.InitConn(ctx); ierr != nil {\n\t\t\treturn ierr\n\t\t}\n\t\treturn cn.ExecuteInitConn(ctx)\n\t}\n\treturn err\n}","preventionTips":["Never call ExecuteInitConn directly on Conns you did not dial via the pool","Run InitConn before ExecuteInitConn in custom pool code","If it reproduces with stock go-redis, report it with a minimal repro and goroutine dump"],"tags":["connection-pool","internal-state","lifecycle"],"backgroundTag":"conn-init-not-set","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}