go-redis/redis · error

redis: ZeroCopyStringCmd cannot be cloned (cmd writes into c

Error message

redis: ZeroCopyStringCmd cannot be cloned (cmd writes into caller-owned memory)

What it means

Returned by ZeroCopyStringCmd.readReply (command.go:1098) when the cmd instance was produced by Clone(). ZeroCopyStringCmd writes its reply directly into a caller-owned buffer (the buf passed to GetToBuffer); a clone can neither share that buffer safely (concurrent sibling writes would race) nor allocate its own (the result would be invisible to the original caller). Clone therefore returns a marked clone that drains the network reply (to keep the connection aligned) and surfaces this explicit error instead of silently-wrong bytes. In practice the path is unreachable through normal flows: GetToBuffer issues a single-key GET that is never fanned out by cluster routing, and NoRetry()==true prevents the retry path from cloning it.

Source

Thrown at command.go:1098

func (cmd *ZeroCopyStringCmd) String() string {
	cmd.await()
	return cmdString(cmd, cmd.n)
}

func (cmd *ZeroCopyStringCmd) readReply(rd *proto.Reader) error {
	// Reset the byte count before reading so a previous successful run
	// can't leak its data through Bytes() if this call errors out before
	// updating cmd.n.
	cmd.n = 0
	if cmd.cloned {
		// A cloned ZeroCopyStringCmd has no usable destination buffer
		// (see Clone for the rationale). Drain the network reply so the
		// connection stays aligned for the next command, then surface a
		// clear error rather than silently producing a wrong result.
		if err := rd.DiscardNext(); err != nil {
			return err
		}
		return fmt.Errorf("redis: ZeroCopyStringCmd cannot be cloned (cmd writes into caller-owned memory)")
	}
	n, err := rd.ReadStringInto(cmd.buf)
	if err != nil {
		return err
	}
	cmd.n = n
	return nil
}

// NoRetry returns true because the response is written directly into the
// caller's buffer. A retry could leave partial data from a failed attempt in
// the buffer, so the caller must handle retries explicitly if needed.
func (cmd *ZeroCopyStringCmd) NoRetry() bool {
	return true
}

// Clone returns a clone that is intentionally non-functional. Cloning a
// ZeroCopyStringCmd has no well-defined semantics: the cmd writes into

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Do not Clone a ZeroCopyStringCmd; if you need a second read, issue a fresh GetToBuffer.
  2. For multi-key/cluster-fanout workloads use the regular Get (StringCmd) which is fully cloneable and retryable.
  3. If using pipelines, remember ZeroCopyStringCmd has NoRetry()==true — handle retries explicitly rather than via the library's automatic clone-and-retry.

Example fix

// before (conceptual — not reachable via normal APIs)
clone := cmd.(*redis.ZeroCopyStringCmd).Clone()
_ = client.Process(ctx, clone) // returns the cannot-be-cloned error

// after — issue a fresh zero-copy read
fresh := client.GetToBuffer(ctx, key, newBuf)
Defensive patterns

Strategy: validation

Validate before calling

// Never clone a ZeroCopyStringCmd. If you need a second read, issue a fresh GetToBuffer.
// Use the regular Get (StringCmd) for any path that may clone (cluster fan-out, retry).
if _, ok := cmd.(*redis.ZeroCopyStringCmd); ok {
    // do not call Clone(); do not feed into cluster fan-out/retry paths
}

Type guard

func isZeroCopy(cmd redis.Cmder) bool {
    _, ok := cmd.(*redis.ZeroCopyStringCmd)
    return ok
}

Prevention

When it happens

Trigger: Theoretically: cluster fan-out routing (osscluster_router.go) attempting to clone a ZeroCopyStringCmd, or a retry path cloning it. Practically unreachable because GetToBuffer is single-key and NoRetry is true. Surfaceable only if custom code forces a Clone on a ZeroCopyStringCmd and then dispatches it.

Common situations: Essentially never seen in normal use. Possible in custom cluster-routing experiments, or if a user manually clones pipeline commands and re-executes them.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/d4b757d4aa447a0b.json. Report an issue: GitHub.