temporalio/temporal · error
%w: %T (expected string)
Error message
%w: %T (expected string)
What it means
PostgreSQL counterpart of the MySQL check: processRowFromDB wraps sqlplugin.ErrInvalidKeywordListDataType when a keyword-list search attribute element decoded from the DB is not a string. The message includes the actual Go type found. Indicates the stored search-attributes JSON does not match the keyword-list schema expectation.
Source
Thrown at common/persistence/sql/sqlplugin/postgresql/visibility.go:203
}
row.StartTime = pdb.converter.FromPostgreSQLDateTime(row.StartTime)
row.ExecutionTime = pdb.converter.FromPostgreSQLDateTime(row.ExecutionTime)
if row.CloseTime != nil {
closeTime := pdb.converter.FromPostgreSQLDateTime(*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
}
}
}
// need to trim the run ID, or otherwise the returned value will
// come with lots of trailing spaces, probably due to the CHAR(64) type
row.RunID = strings.TrimSpace(row.RunID)
return nil
}
View on GitHub (pinned to bde624efd1)
Solutions
- Locate the malformed row and attribute (type shown in the message) and correct the JSON in the visibility table.
- Validate keyword-list values are strings at write time.
- Check for writer-side bugs that serialize non-strings for keyword-list fields.
- If widespread, run a migration script sanitizing keyword-list values to strings.
Defensive patterns
Strategy: type-guard
Validate before calling
// Go: enforce string-only keyword lists on write
for k, vals := range keywordLists {
for _, v := range vals {
if _, ok := v.(string); !ok { return fmt.Errorf("%s: non-string keyword value", k) }
}
} Type guard
func asStrings(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
if err != nil && errors.Is(err, sqlplugin.ErrInvalidKeywordListDataType) {
// identify and sanitize the offending row
return nil, err
} Prevention
- Validate keyword-list values client-side before persistence
- Run data-sanitization migrations after legacy upgrades
- Log the %T detail to locate malformed columns quickly
- Add unit tests covering non-string keyword values in scan paths
When it happens
Trigger: SelectFromVisibility/GetFromVisibility on PostgreSQL reading a row where a keyword-list attribute's []interface{} contains a non-string item — corrupted JSON, non-string values written by a client, or manual data edits.
Common situations: Rows written before validation existed; manual psql edits of search attributes; clients pushing numeric/bool values into keyword-list custom search attributes.
Related errors
- %w: %T (expected string)
- %w: invalid item value type in KeywordList value (got: %T, e
- unsupported type for VisibilitySearchAttributes: %T
- unexpected return type of decodeValueTyped (got: %T, expecte
- requires a StartTime or CloseTime
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/88510d638804261e.
Report an issue: GitHub.