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

  1. Locate the malformed row and attribute (type shown in the message) and correct the JSON in the visibility table.
  2. Validate keyword-list values are strings at write time.
  3. Check for writer-side bugs that serialize non-strings for keyword-list fields.
  4. 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

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


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