hibiken/asynq · error
could not cast to int64
Error message
could not cast %v to int64
What it means
This error is returned by RDB queue-length inspection methods (e.g. queue size queries) when the Lua script (runAllCmd) returns a value that cannot be type-asserted to int64. Redis Lua scripts normally return integers for these counting scripts, so a non-int64 result indicates the script or Redis module behavior deviated from the expected protocol. It is an internal defensive check, not something the caller normally sees.
Solutions
- Verify you are connecting to a standard Redis server that returns integer replies for EVAL scripts
- Check that the asynq version's internal Lua scripts were not modified
- Log the actual value (%v) to see what type the server returned
- Retry the operation; if persistent, report the Redis server/version combination
Example fix
// before
res, err := runAllCmd.Run(ctx, r.client, keys, argv...).Result()
if err != nil { return 0, err }
n, ok := res.(int64)
if !ok { return 0, fmt.Errorf("could not cast %v to int64", res) }
// after
res, err := runAllCmd.Run(ctx, r.client, keys, argv...).Result()
if err != nil { return 0, err }
var n int64
switch v := res.(type) {
case int64: n = v
case string: n, err = strconv.ParseInt(v, 10, 64)
if err != nil { return 0, err }
default: return 0, fmt.Errorf("could not cast %v to int64", res)
} Defensive patterns
Strategy: try-catch
Validate before calling
paused, err := inspector.IsPaused(q)
if err != nil { return err } // ensure Redis is standard and reachable before script calls Type guard
func asInt64(res interface{}) (int64, bool) {
n, ok := res.(int64)
return n, ok
} Try / catch
n, err := inspector.QueueSize(q)
if err != nil {
if strings.Contains(err.Error(), "could not cast") {
// unexpected Redis reply; log value and fall back
}
return err
} Prevention
- Use vanilla Redis, not proxies/forks that alter EVAL replies
- Pin asynq and go-redis versions together
- Log unexpected script replies for diagnosis
- Integration-test against the production Redis version
When it happens
Trigger: Calling an RDB method like QueueSize/Stats that runs the runAllCmd Lua script when the script's Reply value comes back as a string, nil, or other non-int64 type — e.g. a modified/overridden script, a Redis-compatible server returning different reply types, or go-redis returning a wrapper type.
Common situations: Using a Redis-compatible proxy (Twemproxy, KeyDB, Dragonfly) that changes Lua reply types; running against an unexpected Redis version; a forked/patched internal script file.
Related errors
- unexpected return value from script
- unexpected return value from Lua script
- rate.NewSemaphore: unsupported RedisConnOpt type %T
- task already exists
- task ID conflicts with another task
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/2bfff262391ad79a.
Report an issue: GitHub.
Appendix: source
Thrown at internal/rdb/inspect.go:1117
func (r *RDB) runAll(zset, qname string) (int64, error) {
if err := r.checkQueueExists(qname); err != nil {
return 0, err
}
keys := []string{
zset,
base.PendingKey(qname),
}
argv := []interface{}{
base.TaskKeyPrefix(qname),
}
res, err := runAllCmd.Run(context.Background(), r.client, keys, argv...).Result()
if err != nil {
return 0, err
}
n, ok := res.(int64)
if !ok {
return 0, fmt.Errorf("could not cast %v to int64", res)
}
if n == -1 {
return 0, &errors.QueueNotFoundError{Queue: qname}
}
return n, nil
}
// ArchiveAllRetryTasks archives all retry tasks from the given queue and
// returns the number of tasks that were moved.
// If a queue with the given name doesn't exist, it returns QueueNotFoundError.
func (r *RDB) ArchiveAllRetryTasks(qname string) (int64, error) {
var op errors.Op = "rdb.ArchiveAllRetryTasks"
n, err := r.archiveAll(base.RetryKey(qname), base.ArchivedKey(qname), qname)
if errors.IsQueueNotFound(err) {
return 0, errors.E(op, errors.NotFound, err)
}
if err != nil {
return 0, errors.E(op, errors.Internal, err)View on GitHub (pinned to d135f1439b)