{"record":{"id":"ff6289f8d0966499","repo":"temporalio/temporal","slug":"clustermetadata-encountered-local-namesapce-with-f","errorCode":null,"errorMessage":"ClusterMetadata encountered local namesapce with failover version %v","messagePattern":"ClusterMetadata encountered local namesapce with failover version (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/cluster/metadata.go","lineNumber":340,"sourceCode":"\n\tresult := make(map[string]ClusterInformation, len(m.clusterInfo))\n\tmaps.Copy(result, m.clusterInfo)\n\treturn result\n}\n\nfunc (m *metadataImpl) ClusterNameForFailoverVersion(isGlobalNamespace bool, failoverVersion int64) string {\n\tif failoverVersion == common.EmptyVersion {\n\t\t// Local namespace uses EmptyVersion. But local namespace could be promoted to global namespace. Once promoted,\n\t\t// workflows with EmptyVersion could be replicated to other clusters. The receiving cluster needs to know that\n\t\t// those workflows are not from their current cluster.\n\t\tif isGlobalNamespace {\n\t\t\treturn unknownClusterNamePrefix + strconv.Itoa(int(failoverVersion))\n\t\t}\n\t\treturn m.currentClusterName\n\t}\n\n\tif !isGlobalNamespace {\n\t\tpanic(fmt.Sprintf(\n\t\t\t\"ClusterMetadata encountered local namesapce with failover version %v\",\n\t\t\tfailoverVersion,\n\t\t))\n\t}\n\n\tinitialFailoverVersion := failoverVersion % m.failoverVersionIncrement\n\t// Failover version starts with 1.  Zero is an invalid value for failover version\n\tif initialFailoverVersion == common.EmptyVersion {\n\t\tinitialFailoverVersion = m.failoverVersionIncrement\n\t}\n\n\tm.clusterLock.RLock()\n\tdefer m.clusterLock.RUnlock()\n\tclusterName, ok := m.versionToClusterName[initialFailoverVersion]\n\tif !ok {\n\t\tm.logger.Warn(fmt.Sprintf(\n\t\t\t\"Unknown initial failover version %v with given cluster initial failover version map: %v and failover version increment %v.\",\n\t\t\tinitialFailoverVersion,","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/cluster/metadata.go#L322-L358","documentation":"ClusterNameForFailoverVersion resolves which cluster a namespace's failover version belongs to. Global namespaces carry failover versions; local namespaces do not. If the method is invoked with a local (non-global) namespace and a non-nil failover version, the invariants are contradictory and it panics (note the pre-existing typo \"namesapce\" in the message).","triggerScenarios":"Calling ClusterNameForFailoverVersion for a namespace whose NamespaceInfo lacks IsGlobalNamespace but which has a failover version set; corrupted namespace state where a failover version exists without global flag.","commonSituations":"Upgraded/cloned namespace rows with stale failover versions; custom code paths reading failover versions without checking isGlobalNamespace first.","solutions":["Check isGlobalNamespace on the namespace before calling ClusterNameForFailoverVersion, and only call it for global namespaces","Inspect and fix the namespace persistence record so local namespaces have zero failover version","Wrap in recover at high-level request handlers and return an internal-service error instead of crashing"],"exampleFix":"// before\nname := metadata.ClusterNameForFailoverVersion(ns.FailureVersion, ns.IsGlobalNamespace())\n// after\nif !ns.IsGlobalNamespace() {\n  return metadata.GetClusterName() // local namespaces always map to current cluster\n}\nname := metadata.ClusterNameForFailoverVersion(ns.FailureVersion, true)","handlingStrategy":"validation","validationCode":"if !namespace.IsGlobalNamespace(namespaceEntry) {\n  // local namespaces always map to the current cluster; skip the call\n  clusterName := metadata.GetCurrentClusterName()\n}","typeGuard":null,"tryCatchPattern":"func safeClusterNameForVersion(m cluster.Metadata, fv int64, isGlobal bool) (name string, err error) {\n  defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"ClusterNameForFailoverVersion: %v\", r) } }()\n  return m.ClusterNameForFailoverVersion(fv, isGlobal), nil\n}","preventionTips":["Only call ClusterNameForFailoverVersion for global namespaces","Audit namespace persistence records for local namespaces with nonzero failover versions","Handle remote-cluster namespace reads defensively where isGlobalNamespace may be unknown"],"tags":["go","panic","namespace","failover-version"],"backgroundTag":"namespace-failover-version-mismatch","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}