temporalio/temporal · error · sadefs.ErrInvalidType

%w: %v

Error message

%w: %v

What it means

parseValueTyped converts a plain string (from Stringify/Parse of a search attribute) back into a typed value. Its switch handles Bool, Datetime, and UNSPECIFIED; any other declared type (Keyword, Text, KeywordList, Int, etc.) hits the default branch and returns sadefs.ErrInvalidType, because those types are not parseable from a bare string by this single-value parser.

Source

Thrown at common/searchattribute/stringify.go:146

	var err error

	switch t {
	case enumspb.INDEXED_VALUE_TYPE_TEXT,
		enumspb.INDEXED_VALUE_TYPE_KEYWORD,
		enumspb.INDEXED_VALUE_TYPE_KEYWORD_LIST:
		val = valStr
	case enumspb.INDEXED_VALUE_TYPE_INT:
		val, err = strconv.ParseInt(valStr, 10, 64)
	case enumspb.INDEXED_VALUE_TYPE_DOUBLE:
		val, err = strconv.ParseFloat(valStr, 64)
	case enumspb.INDEXED_VALUE_TYPE_BOOL:
		val, err = strconv.ParseBool(valStr)
	case enumspb.INDEXED_VALUE_TYPE_DATETIME:
		val, err = time.Parse(time.RFC3339Nano, valStr)
	case enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED:
		val = parseValueUnspecified(valStr)
	default:
		err = fmt.Errorf("%w: %v", sadefs.ErrInvalidType, t)
	}

	return val, err
}

func parseValueUnspecified(valStr string) any {
	var val any
	var err error

	if val, err = strconv.ParseInt(valStr, 10, 64); err == nil {
	} else if val, err = strconv.ParseBool(valStr); err == nil {
	} else if val, err = strconv.ParseFloat(valStr, 64); err == nil {
	} else if val, err = time.Parse(time.RFC3339Nano, valStr); err == nil {
	} else if isJSONArray(valStr) {
		arr, err := parseJSONArray(valStr, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED)
		if err != nil {
			val = valStr
		} else {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Only run parseValueTyped for Bool/Datetime/Unspecified types; use the appropriate string/JSON path for Keyword/Text.
  2. Route list types (KeywordList) through parseValueOrArray so parseJSONArray handles them.
  3. Verify the type map returns the expected type for the attribute name before parsing.

Example fix

// before
val, err := parseValueTyped(enumspb.INDEXED_VALUE_TYPE_KEYWORD_LIST, "[\"a\"]") // invalid
// after
val, err := parseJSONArray(enumspb.INDEXED_VALUE_TYPE_KEYWORD_LIST, "[\"a\"]")
Defensive patterns

Strategy: type-guard

Validate before calling

switch t {
case enumspb.INDEXED_VALUE_TYPE_BOOL, enumspb.INDEXED_VALUE_TYPE_DATETIME,
    enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED:
default:
    return fmt.Errorf("type %v not parseable as scalar", t)
}

Type guard

func scalarParseable(t enumspb.IndexedValueType) bool {
    return t == enumspb.INDEXED_VALUE_TYPE_BOOL ||
        t == enumspb.INDEXED_VALUE_TYPE_DATETIME ||
        t == enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED
}

Try / catch

if errors.Is(err, sadefs.ErrInvalidType) { /* route to parseJSONArray or string path */ }

Prevention

When it happens

Trigger: Calling Stringify/Parse (via parseValueOrArray -> parseValueTyped) on a search attribute whose declared type is not Bool/Datetime — e.g. parsing "MyKeyword=abc" where the type maps to KEYWORD through the scalar path instead of the array/string path.

Common situations: Using searchattribute.Parse on user-supplied key=value strings where the attribute type resolution yields an unparseable type; feeding KeywordList-typed attributes into the scalar parser instead of parseJSONArray.

Related errors


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