{"record":{"id":"cfd36cc0d142a093","repo":"temporalio/temporal","slug":"dynamic-updateversiontoclustername-err","errorCode":null,"errorMessage":"<dynamic updateVersionToClusterName err>","messagePattern":"<dynamic updateVersionToClusterName err>","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"common/cluster/metadata.go","lineNumber":158,"sourceCode":"\tclusterInfo map[string]ClusterInformation,\n\tclusterMetadataStore persistence.ClusterMetadataManager,\n\trefreshDuration dynamicconfig.DurationPropertyFn,\n\tlogger log.Logger,\n) Metadata {\n\tif len(clusterInfo) == 0 {\n\t\tpanic(\"Empty cluster information\")\n\t} else if len(masterClusterName) == 0 {\n\t\tpanic(\"Master cluster name is empty\")\n\t} else if len(currentClusterName) == 0 {\n\t\tpanic(\"Current cluster name is empty\")\n\t} else if failoverVersionIncrement == 0 || failoverVersionIncrement > math.MaxInt32 {\n\t\tpanic(\"Version increment <= 0 or > 2147483647\")\n\t}\n\n\tversionToClusterName, err := updateVersionToClusterName(clusterInfo, failoverVersionIncrement)\n\tif err != nil {\n\t\t// nolint:forbidigo // matches the other startup-config panics in this constructor\n\t\tpanic(err.Error())\n\t}\n\tif _, ok := clusterInfo[currentClusterName]; !ok {\n\t\tpanic(\"Current cluster is not specified in cluster info\")\n\t}\n\tif _, ok := clusterInfo[masterClusterName]; !ok {\n\t\tpanic(\"Master cluster is not specified in cluster info\")\n\t}\n\n\tcopyClusterInfo := make(map[string]ClusterInformation)\n\tmaps.Copy(copyClusterInfo, clusterInfo)\n\tif refreshDuration == nil {\n\t\trefreshDuration = dynamicconfig.GetDurationPropertyFn(refreshInterval)\n\t}\n\treturn &metadataImpl{\n\t\tstatus:                   common.DaemonStatusInitialized,\n\t\tenableGlobalNamespace:    enableGlobalNamespace,\n\t\tfailoverVersionIncrement: failoverVersionIncrement,\n\t\tmasterClusterName:        masterClusterName,","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/cluster/metadata.go#L140-L176","documentation":"After basic validation, NewMetadata calls updateVersionToClusterName, which builds a failover-version-to-cluster-name map from the supplied clusterInfo. If that helper returns an error (e.g. overlapping initial failover versions or duplicate version assignments across clusters), the constructor panics with the error text. This ensures ambiguous failover version mappings can never reach the running server.","triggerScenarios":"cluster.NewMetadata with a clusterInfo map where two clusters share the same InitialFailoverVersion (producing a collision), or otherwise inconsistent cluster info that updateVersionToClusterName rejects.","commonSituations":"Hand-editing multi-cluster configs and giving two remote clusters the same initial failover version; programmatically generating cluster info where versions are not spaced by failoverVersionIncrement.","solutions":["Assign each cluster in clusterInfo a unique InitialFailoverVersion that is consistent with the failoverVersionIncrement","Log/inspect the panicked error text to identify which cluster/version conflicted","Validate cluster info with updateVersionToClusterName in a preflight check before restarting the service"],"exampleFix":"// before\nclusterInfo := map[string]cluster.ClusterInformation{\n  \"clusterA\": {InitialFailoverVersion: 1},\n  \"clusterB\": {InitialFailoverVersion: 1},\n}\n// after\nclusterInfo := map[string]cluster.ClusterInformation{\n  \"clusterA\": {InitialFailoverVersion: 1},\n  \"clusterB\": {InitialFailoverVersion: 100000000},\n}","handlingStrategy":"validation","validationCode":"seen := map[int64]string{}\nfor name, info := range clusterInfo {\n  if other, dup := seen[info.InitialFailoverVersion]; dup {\n    return fmt.Errorf(\"clusters %s and %s share InitialFailoverVersion %d\", other, name, info.InitialFailoverVersion)\n  }\n  seen[info.InitialFailoverVersion] = name\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Space InitialFailoverVersion values by the failoverVersionIncrement","Lint/generate multi-cluster configs from one source of truth","Run metadata construction in a preflight startup step that logs panics clearly"],"tags":["go","panic","configuration","failover-version"],"backgroundTag":"failover-version-conflict","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}