t8y2/dbx · error

read topic config %s: %v; fallback snapshot: %w

Error message

read topic config %s: %v; fallback snapshot: %w

What it means

readTopicConfig first tries to fetch the single topic's config directly from the broker; when that request fails (err), it falls back to fetching the broker's full topic-config snapshot (fetchAllTopicConfigs). This error is raised only when BOTH paths fail, wrapping the direct error and the fallback error together.

Source

Thrown at agents/drivers/rocketmq/topics.go:587

	}
	if err := json.Unmarshal(repairRocketMQJSON(response.Body), &wrapper); err != nil {
		return nil, err
	}
	return wrapper.TopicConfigTable, nil
}

func readTopicConfig(ctx context.Context, address, topic string) (*topicConfigWire, error) {
	response, err := invokeRemotingWithClient(ctx, address, remoting.NewRequest(remoting.GetTopicConfig, map[string]string{"topic": topic}))
	if err == nil {
		var config topicConfigWire
		if decodeErr := json.Unmarshal(repairRocketMQJSON(response.Body), &config); decodeErr != nil {
			return nil, decodeErr
		}
		return &config, nil
	}
	configs, fallbackErr := fetchAllTopicConfigs(ctx, address)
	if fallbackErr != nil {
		return nil, fmt.Errorf("read topic config %s: %v; fallback snapshot: %w", topic, err, fallbackErr)
	}
	config := configs[topic]
	if config == nil {
		return nil, fmt.Errorf("topic config not found: %s", topic)
	}
	if config.TopicName == "" {
		config.TopicName = topic
	}
	return config, nil
}

func topicAttributesString(attributes map[string]string) string {
	keys := sortedKeys(attributes)
	parts := make([]string, 0, len(keys))
	for _, key := range keys {
		if !strings.HasPrefix(key, "+") && !strings.HasPrefix(key, "-") {
			continue
		}

View on GitHub (pinned to c0390bff16)

Solutions

  1. Read both wrapped errors: the first (%v) is the direct per-topic fetch failure, the second (%w) is the snapshot failure — fix the root cause indicated by the fallback error
  2. Check master broker health/reachability at the resolved address (port 10911 remoting) and retry once the broker is back
  3. Increase config.RequestTimeout if the broker is slow but healthy
  4. Verify ACL credentials permit GET_TOPIC_CONFIG and GET_ALL_TOPIC_CONFIG admin operations

Example fix

// before
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
cfg, err := readTopicConfig(ctx, address, name)
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // larger window
defer cancel()
cfg, err := readTopicConfig(ctx, address, name)
if err != nil {
    // log both wrapped errors; the second is the broker snapshot failure
    log.Printf("readTopicConfig failed: %v", err)
    return retryWithBackoff(func() error { _, err = readTopicConfig(ctx, address, name); return err })
}
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", address, 3*time.Second)
if err != nil {
    return fmt.Errorf("broker %s unreachable, skip config read", address)
}
conn.Close()

Type guard

func isReadTopicConfigErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "read topic config") && strings.Contains(err.Error(), "fallback snapshot")
}

Try / catch

cfg, err := readTopicConfig(ctx, address, topic)
if err != nil {
    if isReadTopicConfigErr(err) {
        time.Sleep(backoff)
        cfg, err = readTopicConfig(ctx, address, topic)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: updatePartitions, getTopicConfig, or alterTopicConfig calls readTopicConfig for a topic while the broker is unreachable or erroring, and the fallback getAllTopicConfig snapshot request also fails (network failure, broker restart, permission rejection).

Common situations: Broker master temporarily down during a rolling restart; remoting timeout due to network congestion; broker rejecting the admin request due to ACL/permission changes; both requests fired within the same short request timeout window during a broker GC pause.

Related errors


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