temporalio/temporal · error

membership upserts require all fields

Error message

membership upserts require all fields

What it means

ErrIncompleteMembershipUpsert is an exported sentinel in common/persistence/cluster_metadata_store.go, returned by UpsertClusterMembership when required fields of the membership record are missing. A membership upsert must contain complete identifying fields (host info etc.) for the record to be meaningful in the ring/membership table.

Source

Thrown at common/persistence/cluster_metadata_store.go:18

package persistence

import (
	"context"
	"errors"

	"go.temporal.io/api/serviceerror"
	persistencespb "go.temporal.io/server/api/persistence/v1"
	"go.temporal.io/server/common/log"
	"go.temporal.io/server/common/persistence/serialization"
)

var (
	// ErrInvalidMembershipExpiry is used when upserting new cluster membership with an invalid duration
	ErrInvalidMembershipExpiry = errors.New("membershipExpiry duration should be atleast 1 second")

	// ErrIncompleteMembershipUpsert is used when upserting new cluster membership with missing fields
	ErrIncompleteMembershipUpsert = errors.New("membership upserts require all fields")
)

type (
	// clusterMetadataManagerImpl implements MetadataManager based on MetadataStore and Serializer
	clusterMetadataManagerImpl struct {
		serializer         serialization.Serializer
		persistence        ClusterMetadataStore
		currentClusterName string
		logger             log.Logger
	}
)

var _ ClusterMetadataManager = (*clusterMetadataManagerImpl)(nil)

// NewClusterMetadataManagerImpl returns new ClusterMetadataManager
func NewClusterMetadataManagerImpl(
	persistence ClusterMetadataStore,
	serializer serialization.Serializer,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Populate all required fields of the upsert request before calling UpsertClusterMembership
  2. Check errors.Is(err, persistence.ErrIncompleteMembershipUpsert) and log the request contents to find the missing field
  3. Ensure host identity (address/ID) is resolved before starting membership broadcast loops

Example fix

// before
_, err := store.UpsertClusterMembership(ctx, &persistence.UpsertClusterMembershipRequest{RecordExpiry: time.Minute})
// after
_, err := store.UpsertClusterMembership(ctx, &persistence.UpsertClusterMembershipRequest{
    RecordExpiry: time.Minute,
    HostID:       hostID,
    HostAddress:  hostAddr,
    Role:         role,
})
Defensive patterns

Strategy: validation

Validate before calling

func completeMembershipUpsert(req *persistence.UpsertClusterMembershipRequest) error {
    if req.HostID == "" || req.HostAddress == "" || req.Role == "" {
        return persistence.ErrIncompleteMembershipUpsert
    }
    return nil
}

Type guard

func hasHostIdentity(h HostInfo) bool { return h.HostID != "" && h.HostAddress != "" }

Try / catch

_, err := manager.UpsertClusterMembership(ctx, req)
if errors.Is(err, persistence.ErrIncompleteMembershipUpsert) {
    logger.Error("incomplete membership upsert", tag.Value(req))
    return err
}

Prevention

When it happens

Trigger: Calling UpsertClusterMembership with a request missing required fields — e.g. empty HostID/HostAddress/Role or similar required members — so the store rejects it as incomplete.

Common situations: Membership broadcaster initialized before host identity is resolved; partially filled request structs in new code or tests; host info providers returning empty values during startup races.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/53e6a9ea4677b0e2. Report an issue: GitHub.