t8y2/dbx · error

partition %d not found for topic %s

Error message

partition %d not found for topic %s

What it means

When sendMessage receives a 'partition' parameter, the driver looks for a target whose QueueID equals it among the topic's writable queues. If none matches, it refuses to send and returns this error. Queue IDs are 0-based and bounded by the topic's writeQueueNums.

Source

Thrown at agents/drivers/rocketmq/messages.go:362

	if err != nil {
		return nil, err
	}
	if len(targets) == 0 {
		return nil, fmt.Errorf("no writable queue for topic %s", topic)
	}
	partition, hasPartition := optionalInt(params, "partition")
	selected := targets[0]
	if hasPartition {
		found := false
		for _, target := range targets {
			if target.QueueID == partition {
				selected = target
				found = true
				break
			}
		}
		if !found {
			return nil, fmt.Errorf("partition %d not found for topic %s", partition, topic)
		}
	}
	command := buildSendMessageCommand(topic, payload, selected.QueueID, params, time.Now().UnixMilli())
	response, err := invokeRemotingAllowCodes(ctx, selected.Address, config.ConnectTimeout, command, 0, 10, 11, 12)
	if err != nil {
		return nil, err
	}
	queueID, _ := strconv.Atoi(response.ExtFields["queueId"])
	queueOffset, _ := strconv.ParseInt(response.ExtFields["queueOffset"], 10, 64)
	return map[string]any{
		"ok": true, "topic": topic, "partition": queueID,
		"offset": queueOffset, "timestamp": time.Now().UnixMilli(),
	}, nil
}

func buildSendMessageCommand(topic string, payload []byte, queueID int, params map[string]any, bornTimestamp int64) *remoting.RemotingCommand {
	message := primitive.NewMessage(topic, payload)
	message.WithProperty(primitive.PropertyUniqueClientMessageIdKeyIndex, primitive.CreateUniqID())

View on GitHub (pinned to c0390bff16)

Solutions

  1. Resolve valid IDs via mqadmin topicRoute <topic> (writeQueueNums); pass partition in 0..writeQueueNums-1.
  2. Omit 'partition' to let the driver use the first available queue (targets[0]).
  3. Restore shrunken queues: mqadmin updateTopic -w <n> -t <topic>.
  4. Make callers re-resolve partition IDs against the current route instead of caching stale values.
  5. Remember IDs are 0-based — a partition equal to writeQueueNums is out of range.

Example fix

// before (topic has 8 queues)
dispatch({"action": "send", "topic": "myTopic", "partition": 16})
// after
dispatch({"action": "send", "topic": "myTopic", "partition": 3})
Defensive patterns

Strategy: validation

Validate before calling

// Validate partition against the topic's writeQueueNums before sending.
route, err := client.ExamineTopicRouteInfo(ctx, topic)
if err != nil { return err }
writeQueues := 0
for _, qd := range route.QueueDatas { writeQueues = max(writeQueues, qd.WriteQueueNums) }
if partition != nil && (*partition < 0 || *partition >= writeQueues) {
    return fmt.Errorf("partition %d out of range 0..%d for topic %s", *partition, writeQueues-1, topic)
}

Type guard

func validPartition(partition, writeQueueNums int) bool {
    return partition >= 0 && partition < writeQueueNums
}

Prevention

When it happens

Trigger: Calling sendMessage via dispatch with params['partition'] set to a queue ID that does not exist for the topic — negative, >= writeQueueNums, or a queue only on an excluded/non-writable broker.

Common situations: Caller hardcodes partition counts from another system (e.g. Kafka) exceeding RocketMQ queue count; writeQueueNums reduced after callers recorded IDs; off-by-one from treating IDs as 1-based; partition recorded from a different topic's route.

Related errors


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