temporalio/temporal · critical

Unknown category type: %v

Error message

Unknown category type: %v

What it means

peekTaskKey computes the next task Key for a category without consuming an ID. It only supports categories of type Immediate and Scheduled; any other CategoryType (e.g. CategoryTypePosterior or a newly added type not yet wired into the key generator) hits the default branch and panics. This is a developer-invariant panic: the category registry accepted the category but the key generator does not know how to key it.

Source

Thrown at service/history/shard/task_key_generator.go:126

		}
	}

	return nil
}

func (a *taskKeyGenerator) peekTaskKey(
	category tasks.Category,
) tasks.Key {
	switch category.Type() {
	case tasks.CategoryTypeImmediate:
		return tasks.NewImmediateKey(a.nextTaskID)
	case tasks.CategoryTypeScheduled:
		return tasks.NewKey(
			a.taskMinScheduledTime,
			a.nextTaskID,
		)
	default:
		panic(fmt.Sprintf("Unknown category type: %v", category.Type()))
	}
}

func (a *taskKeyGenerator) generateTaskKey(
	category tasks.Category,
) (tasks.Key, error) {
	id, err := a.generateTaskID()
	if err != nil {
		return tasks.Key{}, err
	}

	switch category.Type() {
	case tasks.CategoryTypeImmediate:
		return tasks.NewImmediateKey(id), nil
	case tasks.CategoryTypeScheduled:
		return tasks.NewKey(
			a.taskMinScheduledTime,
			id,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Add a switch case in peekTaskKey for the new category type and return an appropriate tasks.Key.
  2. Confirm the correct CategoryType was registered for the category in the task category registry (Immediate vs Scheduled).
  3. If the category should not generate keys through this path, refactor the caller to bypass peekTaskKey for that category.
  4. Search the tasks package for the category definition and ensure its Type() is one supported by the shard's key generator.

Example fix

// before
default:
    panic(fmt.Sprintf("Unknown category type: %v", category.Type()))

// after
case tasks.CategoryTypePosterior:
    return tasks.NewKey(a.taskMinScheduledTime, a.nextTaskID)
default:
    panic(fmt.Sprintf("Unknown category type: %v", category.Type()))
Defensive patterns

Strategy: type-guard

Validate before calling

ct := category.Type()
if ct != tasks.CategoryTypeImmediate && ct != tasks.CategoryTypeScheduled {
    return fmt.Errorf("unsupported category type: %v", ct)
}

Type guard

func keyableCategory(c tasks.Category) bool {
    t := c.Type()
    return t == tasks.CategoryTypeImmediate || t == tasks.CategoryTypeScheduled
}

Prevention

When it happens

Trigger: Calling taskKeyGenerator.peekTaskKey(category) with a tasks.Category whose Type() is not CategoryTypeImmediate or CategoryTypeScheduled — usually when adding a new task category in the tasks package without extending peekTaskKey.

Common situations: Contributors adding a new task category (e.g. a new priority or posterior category) but forgetting to add a switch case; custom forks introducing category types not present upstream.

Related errors


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