temporalio/temporal · error
Unknown field type: %v
Error message
Unknown field type: %v
What it means
During JSON document conversion for Elasticsearch indexing, a type switch over protobuf field value types falls through to a final panic 'Unknown field type: %v' when it encounters a *persistencespb (proto) type it does not explicitly handle. This means the visibility encoder was asked to index a field whose Go/proto type has no mapping to an Elasticsearch field type — almost always after a new field or message type was added without updating the ES visibility encoder.
Source
Thrown at common/persistence/visibility/store/elasticsearch/visibility_store.go:1313
return stringVal, nil
case enumspb.INDEXED_VALUE_TYPE_INT, enumspb.INDEXED_VALUE_TYPE_DOUBLE:
numberVal, isNumber := val.(json.Number)
if !isNumber {
return nil, fmt.Errorf("%w: expected json.Number got %T", errUnexpectedJSONFieldType, val)
}
if t == enumspb.INDEXED_VALUE_TYPE_INT {
return numberVal.Int64()
}
return numberVal.Float64()
case enumspb.INDEXED_VALUE_TYPE_BOOL:
boolVal, isBool := val.(bool)
if !isBool {
return nil, fmt.Errorf("%w: expected bool got %T", errUnexpectedJSONFieldType, val)
}
return boolVal, nil
}
panic(fmt.Sprintf("Unknown field type: %v", t))
}
func ConvertElasticsearchClientError(message string, err error, logger log.Logger) error {
// This message is returned to client, avoiding including too much details.
errMessage := fmt.Sprintf("%s: %s", message, shortErrorMessage(err))
var elasticErr *elastic.Error
switch {
case errors.As(err, &elasticErr):
// Logging the full error message, useful for debugging.
logger.Error(message, tag.ESResponseStatus(elasticErr.Status), tag.Error(err))
switch elasticErr.Status {
case http.StatusBadRequest:
// Returning InvalidArgument error will prevent retry on a caller side.
return serviceerror.NewInvalidArgument(errMessage)
case http.StatusTooManyRequests:
return &serviceerror.ResourceExhausted{
Cause: enumspb.RESOURCE_EXHAUSTED_CAUSE_SYSTEM_OVERLOADED,
Scope: enumspb.RESOURCE_EXHAUSTED_SCOPE_SYSTEM,View on GitHub (pinned to bde624efd1)
Solutions
- Extend the type switch in the ES visibility conversion function to map the missing proto type to its Elasticsearch field representation.
- Upgrade the server/encoder to a version that supports the new field types (fix version skew between frontend/history and the visibility store).
- Identify the offending field from the panic's %v output and either add a converter case or exclude the field from visibility indexing.
- Temporarily disable/roll back the ES visibility write path until the encoder supports the new types.
Example fix
// before
switch t := val.(type) {
case string: ...
case bool: ...
}
panic(fmt.Sprintf("Unknown field type: %v", t))
// after
switch t := val.(type) {
case string: ...
case bool: ...
case *persistencespb.NewFieldType: ...
default:
return nil, fmt.Errorf("%w: unknown field type %T", errUnexpectedJSONFieldType, val)
} Defensive patterns
Strategy: validation
Validate before calling
func fieldSupported(v interface{}) bool {
switch v.(type) {
case string, int64, bool, float64:
return true
default:
logger.Warn("unsupported visibility field type", tag.Type(fmt.Sprintf("%T", v)))
return false
}
} Type guard
func isKnownFieldType(t interface{}) bool { switch t.(type) { case string, int64, bool, float64: return true; default: return false } } Try / catch
// replace the panic default with an error return so the caller can skip/drop the field
unknown, ok := val.(*persistencespb.UnsupportedType)
if !ok { return nil, fmt.Errorf("%w: unknown field type %T", errUnexpectedJSONFieldType, val) } Prevention
- Extend the ES field-type converter whenever new persistencespb field types are added
- Pin server and visibility encoder versions together to avoid skew
- Add CI tests converting a full mutable-state document to ES JSON after proto changes
When it happens
Trigger: Writing workflow visibility data containing a newly introduced proto field type to the Elasticsearch visibility store; the converter's switch on t (field value type) reaches the default panic branch at visibility_store.go:1313.
Common situations: Server upgrade where new persisted proto fields (e.g. new enum/message in persistencespb) are indexed by an ES visibility store but the field-type mapping switch was not extended; running an older ES visibility encoder against state written by a newer server (version skew); custom field additions in forks.
Related errors
- Elasticsearch processor is nil
- config.ESProcessorAckTimeout is nil
- requires a StartTime or CloseTime
- chasm visibilityTaskHandler should not be called directly
- unable to encode single payload: %v
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/39aff9ec7e6bf1b4.
Report an issue: GitHub.