ListWorkflowExecutions operation failed SQL error when using advanced visibility

When using the local Temporal(version 1.21.4) development server I can’t query search attributes containing a slash(/). This will throw an SQL logic error.

I have added some example code that makes it easy to reproduce, just run temporal server start-dev and it should fail immediately.

package main

import (
	"context"
	"fmt"

	"go.temporal.io/api/enums/v1"
	"go.temporal.io/api/operatorservice/v1"
	"go.temporal.io/api/serviceerror"
	"go.temporal.io/api/workflowservice/v1"
	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/workflow"
)

func main() {
	temporalClient, err := client.Dial(client.Options{
		HostPort:  "localhost:7233",
		Namespace: "default",
	})
	if err != nil {
		panic(err)
	}

	_, err = temporalClient.OperatorService().AddSearchAttributes(context.Background(), &operatorservice.AddSearchAttributesRequest{
		SearchAttributes: map[string]enums.IndexedValueType{
			"Workspace": enums.INDEXED_VALUE_TYPE_TEXT,
		},
		Namespace: "default",
	})
	if err != nil {
		if _, ok := err.(*serviceerror.AlreadyExists); !ok {
			panic(err)
		}
	}

	fmt.Println("This one will execute just fine")
	list(temporalClient)
	temporalClient.ExecuteWorkflow(context.Background(), client.StartWorkflowOptions{TaskQueue: "default"}, TestWorkflow)

	fmt.Println("This one will fail")
	list(temporalClient)
}

func list(c client.Client) {
	_, err := c.ListWorkflow(context.Background(), &workflowservice.ListWorkflowExecutionsRequest{
		Namespace: "default",
		Query:     "Workspace = 'terraform/gcp/cluster/cluster-1'",
	})
	if err != nil {
		panic(err)
	}
}

func TestWorkflow(ctx workflow.Context) error {
	return nil
}

{
  "level": "error",
  "ts": "2023-09-01T14:42:34.528+0200",
  "msg": "service failures",
  "operation": "ListWorkflowExecutions",
  "wf-namespace": "A NAMESPACE IS HERE",
  "error": "ListWorkflowExecutions operation failed. Select failed: SQL logic error: fts5: syntax error near \"/\" (1)",
  "logging-call-at": "telemetry.go:330",
  "stacktrace": "go.temporal.io/server/common/log.(*zapLogger).Error\n\tgo.temporal.io/server@v1.21.4/common/log/zap_logger.go:156\ngo.temporal.io/server/common/rpc/interceptor.(*TelemetryInterceptor).handleError\n\tgo.temporal.io/server@v1.21.4/common/rpc/interceptor/telemetry.go:330\ngo.temporal.io/server/common/rpc/interceptor.(*TelemetryInterceptor).UnaryIntercept\n\tgo.temporal.io/server@v1.21.4/common/rpc/interceptor/telemetry.go:171\ngoogle.golang.org/grpc.getChainUnaryHandler.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1179\ngo.temporal.io/server/service/frontend.(*RedirectionInterceptor).handleRedirectAPIInvocation.func2\n\tgo.temporal.io/server@v1.21.4/service/frontend/redirection_interceptor.go:238\ngo.temporal.io/server/service/frontend.(*NoopRedirectionPolicy).WithNamespaceRedirect\n\tgo.temporal.io/server@v1.21.4/service/frontend/dcRedirectionPolicy.go:125\ngo.temporal.io/server/service/frontend.(*RedirectionInterceptor).handleRedirectAPIInvocation\n\tgo.temporal.io/server@v1.21.4/service/frontend/redirection_interceptor.go:235\ngo.temporal.io/server/service/frontend.(*RedirectionInterceptor).Intercept\n\tgo.temporal.io/server@v1.21.4/service/frontend/redirection_interceptor.go:195\ngoogle.golang.org/grpc.getChainUnaryHandler.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1179\ngo.temporal.io/server/common/metrics.NewServerMetricsContextInjectorInterceptor.func1\n\tgo.temporal.io/server@v1.21.4/common/metrics/grpc.go:66\ngoogle.golang.org/grpc.getChainUnaryHandler.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1179\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc.UnaryServerInterceptor.func1\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@v0.42.0/interceptor.go:344\ngoogle.golang.org/grpc.getChainUnaryHandler.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1179\ngo.temporal.io/server/common/rpc/interceptor.(*NamespaceLogInterceptor).Intercept\n\tgo.temporal.io/server@v1.21.4/common/rpc/interceptor/namespace_logger.go:84\ngoogle.golang.org/grpc.getChainUnaryHandler.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1179\ngo.temporal.io/server/common/rpc/interceptor.(*NamespaceValidatorInterceptor).NamespaceValidateIntercept\n\tgo.temporal.io/server@v1.21.4/common/rpc/interceptor/namespace_validator.go:111\ngoogle.golang.org/grpc.getChainUnaryHandler.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1179\ngo.temporal.io/server/common/rpc.ServiceErrorInterceptor\n\tgo.temporal.io/server@v1.21.4/common/rpc/grpc.go:141\ngoogle.golang.org/grpc.chainUnaryInterceptors.func1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1170\ngo.temporal.io/api/workflowservice/v1._WorkflowService_ListWorkflowExecutions_Handler\n\tgo.temporal.io/api@v1.23.0/workflowservice/v1/service.pb.go:1965\ngoogle.golang.org/grpc.(*Server).processUnaryRPC\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1360\ngoogle.golang.org/grpc.(*Server).handleStream\n\tgoogle.golang.org/grpc@v1.57.0/server.go:1737\ngoogle.golang.org/grpc.(*Server).serveStreams.func1.1\n\tgoogle.golang.org/grpc@v1.57.0/server.go:982"
}

When checking out the latest commit I can’t reproduce it anymore. Broken on v1.21.5 as well. Let me check if that also fixes our production environment. Will update this issue next Monday.