temporalio/temporal · error
ClusterMetadata encountered local namesapce with failover ve
Error message
ClusterMetadata encountered local namesapce with failover version %v
What it means
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).
Source
Thrown at common/cluster/metadata.go:340
result := make(map[string]ClusterInformation, len(m.clusterInfo))
maps.Copy(result, m.clusterInfo)
return result
}
func (m *metadataImpl) ClusterNameForFailoverVersion(isGlobalNamespace bool, failoverVersion int64) string {
if failoverVersion == common.EmptyVersion {
// Local namespace uses EmptyVersion. But local namespace could be promoted to global namespace. Once promoted,
// workflows with EmptyVersion could be replicated to other clusters. The receiving cluster needs to know that
// those workflows are not from their current cluster.
if isGlobalNamespace {
return unknownClusterNamePrefix + strconv.Itoa(int(failoverVersion))
}
return m.currentClusterName
}
if !isGlobalNamespace {
panic(fmt.Sprintf(
"ClusterMetadata encountered local namesapce with failover version %v",
failoverVersion,
))
}
initialFailoverVersion := failoverVersion % m.failoverVersionIncrement
// Failover version starts with 1. Zero is an invalid value for failover version
if initialFailoverVersion == common.EmptyVersion {
initialFailoverVersion = m.failoverVersionIncrement
}
m.clusterLock.RLock()
defer m.clusterLock.RUnlock()
clusterName, ok := m.versionToClusterName[initialFailoverVersion]
if !ok {
m.logger.Warn(fmt.Sprintf(
"Unknown initial failover version %v with given cluster initial failover version map: %v and failover version increment %v.",
initialFailoverVersion,View on GitHub (pinned to bde624efd1)
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
Example fix
// before
name := metadata.ClusterNameForFailoverVersion(ns.FailureVersion, ns.IsGlobalNamespace())
// after
if !ns.IsGlobalNamespace() {
return metadata.GetClusterName() // local namespaces always map to current cluster
}
name := metadata.ClusterNameForFailoverVersion(ns.FailureVersion, true) Defensive patterns
Strategy: validation
Validate before calling
if !namespace.IsGlobalNamespace(namespaceEntry) {
// local namespaces always map to the current cluster; skip the call
clusterName := metadata.GetCurrentClusterName()
} Try / catch
func safeClusterNameForVersion(m cluster.Metadata, fv int64, isGlobal bool) (name string, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("ClusterNameForFailoverVersion: %v", r) } }()
return m.ClusterNameForFailoverVersion(fv, isGlobal), nil
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Upgraded/cloned namespace rows with stale failover versions; custom code paths reading failover versions without checking isGlobalNamespace first.
Related errors
- Version increment <= 0 or > 2147483647
- <dynamic updateVersionToClusterName err>
- unable to get namespace details: %w
- <dynamic namespace archival state err>
- Current cluster name is empty
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/ff6289f8d0966499.
Report an issue: GitHub.