hibiken/asynq · error
redis connection is shared so the Client can't be closed…
Error message
redis connection is shared so the Client can't be closed through asynq
What it means
Guard in Client.Close: the client was created with a Redis connection owned elsewhere (e.g. a user-supplied redis.UniversalClient via RedisClientFromClient, or shared with a Server), so asynq will not close it. Closing would break other users of the shared connection; the caller who owns the connection must close it themselves.
Solutions
- Close the redis connection yourself via the shared redis client instead of calling Client.Close()
- Create the Client with NewClient (own connection) rather than NewClientFromRedisClient if you want asynq to manage closing
Defensive patterns
Strategy: type-guard
When it happens
Trigger: Thrown at client.go:352 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/400eb0168cb1e9a8.
Report an issue: GitHub.
Appendix: source
Thrown at client.go:352
const (
// Default max retry count used if nothing is specified.
defaultMaxRetry = 25
// Default timeout used if both timeout and deadline are not specified.
defaultTimeout = 30 * time.Minute
)
// Value zero indicates no timeout and no deadline.
var (
noTimeout time.Duration = 0
noDeadline time.Time = time.Unix(0, 0)
)
// Close closes the connection with redis.
func (c *Client) Close() error {
if c.sharedConnection {
return fmt.Errorf("redis connection is shared so the Client can't be closed through asynq")
}
return c.broker.Close()
}
// Enqueue enqueues the given task to a queue.
//
// Enqueue returns TaskInfo and nil error if the task is enqueued successfully, otherwise returns a non-nil error.
//
// The argument opts specifies the behavior of task processing.
// If there are conflicting Option values the last one overrides others.
// Any options provided to NewTask can be overridden by options passed to Enqueue.
// By default, max retry is set to 25 and timeout is set to 30 minutes.
//
// If no ProcessAt or ProcessIn options are provided, the task will be pending immediately.
//
// Enqueue uses context.Background internally; to specify the context, use EnqueueContext.
func (c *Client) Enqueue(task *Task, opts ...Option) (*TaskInfo, error) {
return c.EnqueueContext(context.Background(), task, opts...)View on GitHub (pinned to d135f1439b)