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

  1. Extend the type switch in the ES visibility conversion function to map the missing proto type to its Elasticsearch field representation.
  2. Upgrade the server/encoder to a version that supports the new field types (fix version skew between frontend/history and the visibility store).
  3. Identify the offending field from the panic's %v output and either add a converter case or exclude the field from visibility indexing.
  4. 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

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


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