temporalio/temporal · error

unknown persistence task predicate type: %v

Error message

unknown persistence task predicate type: %v

What it means

FromPersistencePredicate is the inverse of ToPersistencePredicate: it maps a persistencespb.Predicate back to a tasks.Predicate by predicate type enum. The default branch panics when the stored PREDICATE_TYPE value has no known deserializer.

Source

Thrown at service/history/queues/convert.go:157

		return FromPersistenceEmptyPredicate(predicate.GetEmptyPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_AND:
		return FromPersistenceAndPredicate(predicate.GetAndPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_OR:
		return FromPersistenceOrPredicate(predicate.GetOrPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_NOT:
		return FromPersistenceNotPredicate(predicate.GetNotPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_NAMESPACE_ID:
		return FromPersistenceNamespaceIDPredicate(predicate.GetNamespaceIdPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_TASK_TYPE:
		return FromPersistenceTaskTypePredicate(predicate.GetTaskTypePredicateAttributes())
	case enumsspb.PREDICATE_TYPE_DESTINATION:
		return FromPersistenceDestinationPredicate(predicate.GetDestinationPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_OUTBOUND_TASK_GROUP:
		return FromPersistenceOutboundTaskGroupPredicate(predicate.GetOutboundTaskGroupPredicateAttributes())
	case enumsspb.PREDICATE_TYPE_OUTBOUND_TASK:
		return FromPersistenceOutboundTaskPredicate(predicate.GetOutboundTaskPredicateAttributes())
	default:
		panic(fmt.Sprintf("unknown persistence task predicate type: %v", predicate.GetPredicateType()))
	}
}

func ToPersistenceUniversalPredicate(
	_ *predicates.UniversalImpl[tasks.Task],
) *persistencespb.Predicate {
	return &persistencespb.Predicate{
		PredicateType: enumsspb.PREDICATE_TYPE_UNIVERSAL,
		Attributes:    &persistencespb.Predicate_UniversalPredicateAttributes{},
	}
}

func FromPersistenceUniversalPredicate(
	_ *persistencespb.UniversalPredicateAttributes,
) tasks.Predicate {
	return predicates.Universal[tasks.Task]()
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Upgrade the service version so it recognizes the persisted PREDICATE_TYPE
  2. Add the missing enumsspb.PREDICATE_TYPE case mapping to a FromPersistence... function and regenerate code
  3. Inspect the offending persistence record; if corrupt, delete/rewrite it so the default predicate (ALL) is used
  4. Ensure proto-generated code is up to date (make proto / make update-go-api) so enum values match

Example fix

// before
default:
    panic(fmt.Sprintf("unknown persistence task predicate type: %v", predicate.GetPredicateType()))
// after
case enumsspb.PREDICATE_TYPE_MY_NEW:
    return FromPersistenceMyNewPredicate(predicate.GetMyNewPredicateAttributes())
default:
    return predicates.EmptyTaskPredicate(), nil // or log + fall back
Defensive patterns

Strategy: validation

Validate before calling

if p.GetPredicateType() == enumsspb.PREDICATE_TYPE_UNSPECIFIED ||
    !knownPredicateTypes[p.GetPredicateType()] {
    // fall back to empty/ALL predicate instead of deserializing
    return predicates.EmptyTaskPredicate()
}

Try / catch

func safeFromPersistence(p *persistencespb.Predicate) (out tasks.Predicate) {
    defer func() {
        if r := recover(); r != nil {
            out = predicates.EmptyTaskPredicate()
        }
    }()
    out = queues.FromPersistencePredicate(p)
    return
}

Prevention

When it happens

Trigger: Reading a predicate blob from persistence (e.g. task queue metadata / rate limiter scope) whose PREDICATE_TYPE was written by a newer or patched temporal version, is zero/unset, or is corrupt.

Common situations: Rolling upgrades or downgrades where a new predicate type was persisted by newer code and read by older code; corrupted or hand-edited persistence rows; enums added to proto but converter not regenerated.

Related errors


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