temporalio/temporal · error
%w: %T (expected string)
Error message
%w: %T (expected string)
What it means
Returned by processRowFromDB (MySQL visibility store) when a keyword-list search attribute value read from the DB contains an element that is not a Go string. It wraps sqlplugin.ErrInvalidKeywordListDataType and includes the actual Go type found (%T). This indicates corrupted or unexpectedly encoded data in the search attributes JSON column.
Source
Thrown at common/persistence/sql/sqlplugin/mysql/visibility.go:340
}
row.StartTime = mdb.converter.FromMySQLDateTime(row.StartTime)
row.ExecutionTime = mdb.converter.FromMySQLDateTime(row.ExecutionTime)
if row.CloseTime != nil {
closeTime := mdb.converter.FromMySQLDateTime(*row.CloseTime)
row.CloseTime = &closeTime
}
if row.SearchAttributes != nil {
for saName, saValue := range *row.SearchAttributes {
switch typedSaValue := saValue.(type) {
case []any:
// the only valid type is slice of strings
strSlice := make([]string, len(typedSaValue))
for i, item := range typedSaValue {
switch v := item.(type) {
case string:
strSlice[i] = v
default:
return fmt.Errorf("%w: %T (expected string)", sqlplugin.ErrInvalidKeywordListDataType, v)
}
}
(*row.SearchAttributes)[saName] = strSlice
default:
// no-op
}
}
}
return nil
}
View on GitHub (pinned to bde624efd1)
Solutions
- Identify the offending attribute name and row (from the %T type in the message) and inspect its JSON in the visibility table.
- Fix or delete the malformed row's search attributes data.
- Validate search attribute values are strings before writing keyword-list attributes.
- Upgrade/patch the writer that allowed non-string values into keyword-list fields.
Example fix
// before: writing unvalidated values
sa["KeywordListField"] = []interface{}{123}
// after: enforce strings
if _, ok := v.(string); !ok { return fmt.Errorf("keyword list value must be string") } Defensive patterns
Strategy: type-guard
Validate before calling
// Go: validate keyword list values before writing
for _, v := range values {
if _, ok := v.(string); !ok {
return fmt.Errorf("keyword list values must be strings, got %T", v)
}
} Type guard
func isStringSlice(items []interface{}) ([]string, bool) {
out := make([]string, len(items))
for i, v := range items {
s, ok := v.(string)
if !ok { return nil, false }
out[i] = s
}
return out, true
} Try / catch
// Go
row, err := store.SelectFromVisibility(ctx, req)
if err != nil && errors.Is(err, sqlplugin.ErrInvalidKeywordListDataType) {
// data corruption path: skip/quarantine the row, alert
return nil, fmt.Errorf("corrupt keyword-list data: %w", err)
} Prevention
- Validate custom search attribute types at ingestion time
- Never hand-edit search attributes JSON in the DB
- Monitor ErrInvalidKeywordListDataType occurrences as data-corruption signals
- Pin writer versions so serialization bugs are caught in tests
When it happens
Trigger: SelectFromVisibility or GetFromVisibility decoding a row whose keyword-list SearchAttributes JSON contains a non-string element — e.g. a numeric or boolean value stored under a keyword-list key, typically from a writer bug, manual row edits, or a driver returning []interface{} of non-strings.
Common situations: Corrupted rows after manual DB manipulation; data written by an older/buggy version; misuse of a keyword-list field with non-string values via custom search attribute ingestion.
Related errors
- %w: %T (expected string)
- %w: invalid item value type in KeywordList value (got: %T, e
- unable to insert custom search attributes: %w
- unable to upsert custom search attributes: %w
- unsupported type for VisibilitySearchAttributes: %T
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/e9013007111cc251.
Report an issue: GitHub.