temporalio/temporal · critical

unsupported partition kind:

Error message

unsupported partition kind: 

What it means

PhysicalTaskQueueKey partition-kind formatting supports only the defined TaskQueuePartition kinds; PersistenceName panics when a key has an unexpected Kind. The empty string in the message means Kind() returned an enum value whose String() is empty — i.e. an unset/zero-valued kind slipped through into partition-name resolution.

Source

Thrown at service/matching/physical_task_queue_key.go:144

			return nonRootPartitionPrefix + baseName + partitionDelimiter + q.version.versionSet + versionSetDelimiter + strconv.Itoa(p.PartitionId())
		}

		if len(q.version.deploymentSeriesName) > 0 {
			encodedBuildId := base64.RawURLEncoding.EncodeToString([]byte(q.version.buildId))
			encodedDeploymentName := base64.RawURLEncoding.EncodeToString([]byte(q.version.deploymentSeriesName))
			return nonRootPartitionPrefix + baseName + partitionDelimiter + encodedDeploymentName + deploymentNameDelimiter + encodedBuildId + buildIdDelimiter + strconv.Itoa(p.PartitionId())
		} else if len(q.version.buildId) > 0 {
			encodedBuildId := base64.URLEncoding.EncodeToString([]byte(q.version.buildId))
			return nonRootPartitionPrefix + baseName + partitionDelimiter + encodedBuildId + buildIdDelimiter + strconv.Itoa(p.PartitionId())
		}

		// unversioned
		if p.IsRoot() {
			return baseName
		}
		return nonRootPartitionPrefix + baseName + partitionDelimiter + strconv.Itoa(p.PartitionId())
	default:
		panic("unsupported partition kind: " + p.Kind().String())
	}
}

func (q *PhysicalTaskQueueKey) IsVersioned() bool {
	return q.version.IsVersioned()
}

// Version returns a pointer to the physical queue version key. Caller must not manipulate the
// returned value.
func (q *PhysicalTaskQueueKey) Version() PhysicalTaskQueueVersion {
	return q.version
}

func (v PhysicalTaskQueueVersion) IsVersioned() bool {
	return v.versionSet != "" || v.buildId != ""
}

func (v PhysicalTaskQueueVersion) Deployment() *deploymentpb.Deployment {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Find the code path constructing the key and ensure the partition kind is explicitly set from TaskQueueKind (normal/stack) before calling PersistenceName
  2. Check persistence rows for a kind value outside the known enum range and migrate them
  3. Add a constructor/validator that rejects zero-valued kinds early instead of letting them reach PersistenceName

Example fix

// before
key := taskqueue.NewPhysicalTaskQueueKey(p.Partition{})
name := key.PersistenceName()

// after
p := taskqueue.NewRootPartitionFromTaskQueueInfo(ti)
key := taskqueue.NewPhysicalTaskQueueKey(p)
name := key.PersistenceName()
Defensive patterns

Strategy: validation

Validate before calling

if p.Kind() == taskqueue.PartitionKindUnspecified {
	return fmt.Errorf("partition kind not set before PersistenceName")
}

Type guard

func validPartitionKind(p taskqueue.Partition) bool {
	switch p.Kind() {
	case taskqueue.PartitionKindNormal, taskqueue.PartitionKindStack:
		return true
	default:
		return false
	}
}

Try / catch

func safePersistenceName(key taskqueue.PhysicalTaskQueueKey) (name string, err error) {
	defer func() {
		if rec := recover(); rec != nil {
			err = fmt.Errorf("partition name panic: %v", rec)
		}
	}()
	return key.PersistenceName(), nil
}

Prevention

When it happens

Trigger: getQueueDataByKey receives a PhysicalTaskQueueKey whose partition kind was never set (zero value) or was constructed from persistence/DB data with an out-of-range kind enum, hitting the default branch of the kind switch.

Common situations: Task queue data rows in persistence with unrecognized kind values (schema/enum drift between versions); code paths building PhysicalTaskQueueKey literals without setting the kind field; restoring old DB rows after enum renumbering.

Related errors


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