{"record":{"id":"1ac45ffc05184dae","repo":"t8y2/dbx","slug":"read-topic-config-s-v-fallback-snapshot-w","errorCode":null,"errorMessage":"read topic config %s: %v; fallback snapshot: %w","messagePattern":"read topic config (.+?): (.+?); fallback snapshot: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/rocketmq/topics.go","lineNumber":587,"sourceCode":"\t}\n\tif err := json.Unmarshal(repairRocketMQJSON(response.Body), &wrapper); err != nil {\n\t\treturn nil, err\n\t}\n\treturn wrapper.TopicConfigTable, nil\n}\n\nfunc readTopicConfig(ctx context.Context, address, topic string) (*topicConfigWire, error) {\n\tresponse, err := invokeRemotingWithClient(ctx, address, remoting.NewRequest(remoting.GetTopicConfig, map[string]string{\"topic\": topic}))\n\tif err == nil {\n\t\tvar config topicConfigWire\n\t\tif decodeErr := json.Unmarshal(repairRocketMQJSON(response.Body), &config); decodeErr != nil {\n\t\t\treturn nil, decodeErr\n\t\t}\n\t\treturn &config, nil\n\t}\n\tconfigs, fallbackErr := fetchAllTopicConfigs(ctx, address)\n\tif fallbackErr != nil {\n\t\treturn nil, fmt.Errorf(\"read topic config %s: %v; fallback snapshot: %w\", topic, err, fallbackErr)\n\t}\n\tconfig := configs[topic]\n\tif config == nil {\n\t\treturn nil, fmt.Errorf(\"topic config not found: %s\", topic)\n\t}\n\tif config.TopicName == \"\" {\n\t\tconfig.TopicName = topic\n\t}\n\treturn config, nil\n}\n\nfunc topicAttributesString(attributes map[string]string) string {\n\tkeys := sortedKeys(attributes)\n\tparts := make([]string, 0, len(keys))\n\tfor _, key := range keys {\n\t\tif !strings.HasPrefix(key, \"+\") && !strings.HasPrefix(key, \"-\") {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/rocketmq/topics.go#L569-L605","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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","Check master broker health/reachability at the resolved address (port 10911 remoting) and retry once the broker is back","Increase config.RequestTimeout if the broker is slow but healthy","Verify ACL credentials permit GET_TOPIC_CONFIG and GET_ALL_TOPIC_CONFIG admin operations"],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\ndefer cancel()\ncfg, err := readTopicConfig(ctx, address, name)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // larger window\ndefer cancel()\ncfg, err := readTopicConfig(ctx, address, name)\nif err != nil {\n    // log both wrapped errors; the second is the broker snapshot failure\n    log.Printf(\"readTopicConfig failed: %v\", err)\n    return retryWithBackoff(func() error { _, err = readTopicConfig(ctx, address, name); return err })\n}","handlingStrategy":"retry","validationCode":"conn, err := net.DialTimeout(\"tcp\", address, 3*time.Second)\nif err != nil {\n    return fmt.Errorf(\"broker %s unreachable, skip config read\", address)\n}\nconn.Close()","typeGuard":"func isReadTopicConfigErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"read topic config\") && strings.Contains(err.Error(), \"fallback snapshot\")\n}","tryCatchPattern":"cfg, err := readTopicConfig(ctx, address, topic)\nif err != nil {\n    if isReadTopicConfigErr(err) {\n        time.Sleep(backoff)\n        cfg, err = readTopicConfig(ctx, address, topic)\n    }\n    if err != nil { return err }\n}","preventionTips":["Increase RequestTimeout for slow or heavily loaded brokers","Avoid altering topic config during broker rolling restarts","Ensure ACLs allow both GET_TOPIC_CONFIG and GET_ALL_TOPIC_CONFIG","Parse both wrapped errors to identify which request path failed"],"tags":["rocketmq","broker","timeout","fallback"],"backgroundTag":"broker-request-failed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}