t8y2/dbx · error

invalid ZooKeeper string vector length %d

Error message

invalid ZooKeeper string vector length %d

What it means

strings() decodes a ZooKeeper 'vector of strings' (used by getChildren). A length prefix of -1 is treated as a null vector (nil result); a negative length other than -1, or a length exceeding zooKeeperMaxFrameSize/4, is rejected with this error. It prevents absurd string-vector counts from driving huge allocations or long loops over a corrupted stream.

Source

Thrown at agents/drivers/hive-go/zookeeper_protocol.go:514

	}
	return append([]byte(nil), value...), nil
}

func (decoder *zooKeeperDecoder) string() (string, error) {
	value, err := decoder.bytes()
	return string(value), err
}

func (decoder *zooKeeperDecoder) strings() ([]string, error) {
	length, err := decoder.int32()
	if err != nil {
		return nil, err
	}
	if length == -1 {
		return nil, nil
	}
	if length < -1 || length > zooKeeperMaxFrameSize/4 {
		return nil, fmt.Errorf("invalid ZooKeeper string vector length %d", length)
	}
	values := make([]string, 0, length)
	for index := int32(0); index < length; index++ {
		value, valueErr := decoder.string()
		if valueErr != nil {
			return nil, valueErr
		}
		values = append(values, value)
	}
	return values, nil
}

func (decoder *zooKeeperDecoder) stat() (*zk.Stat, error) {
	stat := &zk.Stat{}
	var err error
	if stat.Czxid, err = decoder.int64(); err != nil {
		return nil, err
	}

View on GitHub (pinned to c0390bff16)

Solutions

  1. Reconnect the client to reset stream alignment; a single decode error usually means the whole connection is desynced.
  2. Reduce the child count on the offending znode (archived old children, use a sharded layout) so replies stay well under the cap.
  3. Check middleboxes (proxies, load balancers, NAT gateways) for response truncation; test from the same host as the server.
  4. Confirm the endpoint is a real ZooKeeper server (four-letter 'srvr' command or nc to port 2181).
  5. If legitimately huge listings are needed, raise zooKeeperMaxFrameSize/4's effective limit and redeploy with adequate memory.

Example fix

// before
children, err := client.Children("/tasks") // 1M children -> reply exceeds cap
// after
// shard the znode so each getChildren reply is small
children0, _ := client.Children("/tasks/shard-0")
children1, _ := client.Children("/tasks/shard-1")
Defensive patterns

Strategy: validation

Validate before calling

// keep directories small enough that getChildren replies stay tiny
children, err := client.Children(parent)
if err == nil && len(children) > 50000 {
	log.Warnf("znode %s has %d children; consider sharding", parent, len(children))
}

Type guard

func isInvalidVectorLength(err error) bool {
	return err != nil && strings.Contains(err.Error(), "invalid ZooKeeper string vector length")
}

Try / catch

children, err := client.Children(path)
if err != nil {
	if isInvalidVectorLength(err) {
		client.Close()
		client, err = hive.Dial(connStr) // desynced stream: reconnect
		if err == nil {
			children, err = client.Children(shardOf(path)) // retry smaller
		}
	}
	if err != nil {
		return fmt.Errorf("zk children %s: %w", path, err)
	}
}

Prevention

When it happens

Trigger: Any Children() call where the response's vector length prefix is < -1 or above zooKeeperMaxFrameSize/4 — i.e. a corrupted/malformed getChildren reply or a desynchronized byte stream.

Common situations: Server or proxy truncating large getChildren replies (a directory with very many children), firewall/NAT mangling the TCP stream, protocol desync from an earlier failed read on the same connection, or connecting to a non-ZooKeeper endpoint.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/0b28582302c0a787. Report an issue: GitHub.