thanos-io/thanos · error

failed to convert resp to string

Error message

failed to convert %s resp to string

What it means

RedisClient.MGet converts each non-nil MGET reply message to a string; if rueidis's m.ToString() fails for a key, the client returns this error identifying which key's reply could not be converted. It indicates the server returned an unexpected reply type (e.g. an error message) for that key.

Solutions

  1. Check the key named in the error with redis-cli TYPE <key> — remove/fix non-string values written by other components.
  2. Use a cluster-aware Redis client if replies contain MOVED/ASK errors.
  3. Harden the caller to treat conversion failures as cache misses instead of aborting the batch.
  4. Audit writers that may store complex types under keys this cache expects to own.

Example fix

// before
r, err := m.ToString()
if err != nil { return nil, errors.Errorf("failed to convert %s resp to string", k) }
// after
typeGuard = func(m rueidis.RedisMessage) bool { return !m.IsNil() && !m.IsError() }
Defensive patterns

Strategy: type-guard

Type guard

func isStringReply(m rueidis.RedisMessage) bool {
    return !m.IsNil() && !m.IsError()
}

Try / catch

vals, err := client.MGet(ctx, keys)
if err != nil && strings.Contains(err.Error(), "failed to convert") {
    key := extractKeyFromErr(err)
    log.Warnf("non-string value at %s — treat as miss", key)
    vals = nil
}

Prevention

When it happens

Trigger: Calling MGet() where the reply for key k is neither nil nor a bulk/simple string — typically an error reply (WRONGTYPE, MOVED/ASK in cluster mode) surfaced as a message that cannot convert to string.

Common situations: Key holds a non-string Redis type (hash/list) because another writer overwrote it; cluster redirect errors when using a plain client against a cluster; corrupted proxy replies.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/7e187f619af0206d. Report an issue: GitHub.

Appendix: source

Thrown at internal/cortex/chunk/cache/redis_client.go:153

	ret := make([][]byte, 0, len(keys))

	mgetRet, err := rueidis.MGet(c.rdb, ctx, keys)
	if err != nil {
		return nil, err
	}
	for _, k := range keys {
		m, ok := mgetRet[k]
		if !ok {
			return nil, errors.Errorf("not found key %s in results", k)
		}
		if m.IsNil() {
			ret = append(ret, nil)
			continue
		}
		r, err := m.ToString()
		if err != nil {
			return nil, errors.Errorf("failed to convert %s resp to string", k)
		}
		ret = append(ret, stringToBytes(r))
	}

	return ret, nil
}

func (c *RedisClient) Close() error {
	c.rdb.Close()
	return nil
}

func stringToBytes(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(
		&struct {
			string
			Cap int
		}{s, len(s)},

View on GitHub (pinned to 35b8b99117)