SigNoz/signoz · error

unsupported operation, exists and not exists can only be app

Error message

unsupported operation, exists and not exists can only be applied on custom attributes or string type columns

What it means

existsSubQueryForFixedColumn in the v4 traces query builder: exists/not-exists on traces is implemented as comparing the column against the empty string, which is only meaningful for custom attributes or string-typed columns. Any other fixed column type is rejected.

Source

Thrown at pkg/query-service/app/traces/v4/query_builder.go:101

func getSelectLabels(groupBy []v3.AttributeKey) string {
	var labels []string
	for _, tag := range groupBy {
		name := getColumnName(tag, true)
		labels = append(labels, fmt.Sprintf(" %s as `%s`", name, tag.Key))
	}
	return strings.Join(labels, ",")
}

// TODO(nitya): use the _exists columns as well in the future similar to logs
func existsSubQueryForFixedColumn(key v3.AttributeKey, op v3.FilterOperator) (string, error) {
	if key.DataType == v3.AttributeKeyDataTypeString {
		if op == v3.FilterOperatorExists {
			return fmt.Sprintf("%s %s ''", getColumnName(key, true), tracesOperatorMappingV3[v3.FilterOperatorNotEqual]), nil
		} else {
			return fmt.Sprintf("%s %s ''", getColumnName(key, true), tracesOperatorMappingV3[v3.FilterOperatorEqual]), nil
		}
	} else {
		return "", fmt.Errorf("unsupported operation, exists and not exists can only be applied on custom attributes or string type columns")
	}
}

func BuildTracesFilterQuery(fs *v3.FilterSet, skipAllowed bool) (string, error) {
	var conditions []string

	if fs != nil && len(fs.Items) != 0 {
		for _, item := range fs.Items {

			// skip if it's a resource attribute or Span search scope attribute
			// adding skipAllowed because traceFunnels requires the resource one as well.
			if skipAllowed && (item.Key.Type == v3.AttributeKeyTypeResource || item.Key.Type == v3.AttributeKeyTypeSpanSearchScope) {
				continue
			}

			val := item.Value
			// generate the key
			columnName := getColumnName(item.Key, true)

View on GitHub (pinned to 5069bf80b0)

Solutions

  1. Drop the exists/nexists filter on the non-string fixed column
  2. Use an explicit comparison (e.g. > 0) for numeric columns
  3. Apply exists only to string columns or custom attributes

Example fix

// before
{"key":"duration_ns","operator":"nexists"}

// after
{"key":"http.route","operator":"nexists"} // string/custom attribute
Defensive patterns

Strategy: type-guard

Validate before calling

if (op == v3.FilterOperatorExists || op == v3.FilterOperatorNexists) && !existsAllowedV4(key) {
    return fmt.Errorf("exists not supported on %s", key.Key)
}

Type guard

func existsAllowedV4(key v3.AttributeKey) bool {
    return key.Type == v3.AttributeKeyTypeTag || key.DataType == v3.AttributeKeyDataTypeString
}

Prevention

When it happens

Trigger: Using exists or not exists on a fixed traces column of non-string type (numeric, bool) in a query routed through the v4 traces builder.

Common situations: Generic dashboard filter builders applying exists to every column; saved views created before this restriction was enforced.

Related errors


AI-assisted analysis of SigNoz/signoz@5069bf80b0 (2026-08-28). Data as JSON: /api/errors/1d11e75fc07c7238. Report an issue: GitHub.