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

  1. Verify you are connecting to a standard Redis server that returns integer replies for EVAL scripts
  2. Check that the asynq version's internal Lua scripts were not modified
  3. Log the actual value (%v) to see what type the server returned
  4. 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

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


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)