temporalio/temporal · error · converter.ErrUnableToDecode

%w: invalid item value type in KeywordList value (got: %T, e

Error message

%w: invalid item value type in KeywordList value (got: %T, expected: string)

What it means

DecodeKeywordList wraps converter.ErrUnableToDecode when an element of the decoded value is not a Go string. After the payload converter produces []any, each item must be a string for a KEYWORD_LIST; any other item type (number, bool, nested list) aborts with the offending value's dynamic type reported. Note the message prints the whole dv value's type, not the item's, which can be slightly misleading.

Source

Thrown at common/searchattribute/sadefs/encode_value.go:160

	if err != nil {
		return nil, err
	}
	if dv == nil {
		return nil, nil
	}
	// Validate that every value is a string.
	tdv, ok := dv.([]any)
	if !ok {
		//nolint:forbidigo // this should never happen
		panic(fmt.Sprintf("unexpected return type of decodeValueTyped (got: %T, expected: []any)", dv))
	}
	res := make([]string, len(tdv))
	for i, v := range tdv {
		switch vt := v.(type) {
		case string:
			res[i] = vt
		default:
			return nil, fmt.Errorf(
				"%w: invalid item value type in KeywordList value (got: %T, expected: string)",
				converter.ErrUnableToDecode,
				dv,
			)
		}
	}
	return res, nil
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Ensure the encoder writes only string items into KeywordList values (use sadefs.EncodeValue with []string).
  2. Coerce/convert numeric or bool items to strings at the producer before encoding.
  3. Inspect the payload items (the offending value is named in the error) and fix the writer.

Example fix

// before
items := []any{"a", 42}
payload, _ := converter.DefaultDataConverter.ToPayload(items)
// after
payload, _ := sadefs.EncodeValue([]string{"a", "42"}, false)
Defensive patterns

Strategy: type-guard

Validate before calling

for _, v := range items {
    if _, ok := v.(string); !ok {
        return fmt.Errorf("keyword list contains non-string item")
    }
}

Type guard

func isStringList(items []any) bool {
    for _, v := range items {
        if _, ok := v.(string); !ok {
            return false
        }
    }
    return true
}

Try / catch

if errors.Is(err, converter.ErrUnableToDecode) { /* inspect payload items and fix producer */ }

Prevention

When it happens

Trigger: Calling DecodeKeywordList (or Validate) on a payload whose list contains non-string items — e.g. a mixed-type list encoded via a generic JSON converter or hand-built temporal/api common Payload.

Common situations: Values built by external tools writing raw payloads; data migrated from another system where the field held heterogeneous types; SDK versions encoding nil/non-string items.

Related errors


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