temporalio/temporal · error

invalid value: %s

Error message

invalid value: %s

What it means

In the S3 archive query parser, the right-hand side of each WHERE comparison must be a plain SQL literal (sqlparser.SQLVal). If the right side is a subquery, function call, column reference, or complex expression, convertComparisonExpr returns this error. Values must be static literals (strings/timestamps) extractable by the parser.

Source

Thrown at common/archiver/s3store/query_parser.go:121

}

func (p *queryParser) convertAndExpr(andExpr *sqlparser.AndExpr, parsedQuery *parsedQuery) error {
	if err := p.convertWhereExpr(andExpr.Left, parsedQuery); err != nil {
		return err
	}
	return p.convertWhereExpr(andExpr.Right, parsedQuery)
}

func (p *queryParser) convertComparisonExpr(compExpr *sqlparser.ComparisonExpr, parsedQuery *parsedQuery) error {
	colName, ok := compExpr.Left.(*sqlparser.ColName)
	if !ok {
		return fmt.Errorf("invalid filter name: %s", sqlparser.String(compExpr.Left))
	}
	colNameStr := sqlparser.String(colName)
	op := compExpr.Operator
	valExpr, ok := compExpr.Right.(*sqlparser.SQLVal)
	if !ok {
		return fmt.Errorf("invalid value: %s", sqlparser.String(compExpr.Right))
	}
	valStr := sqlparser.String(valExpr)

	switch colNameStr {
	case WorkflowTypeName, WorkflowType:
		val, err := sqlquery.ExtractStringValue(valStr)
		if err != nil {
			return err
		}
		if op != "=" {
			return fmt.Errorf("only operation = is support for %s", colNameStr)
		}
		if parsedQuery.workflowType != nil {
			return fmt.Errorf("can not query %s multiple times", colNameStr)
		}
		parsedQuery.workflowType = new(val)
	case WorkflowID:
		val, err := sqlquery.ExtractStringValue(valStr)

View on GitHub (pinned to bde624efd1)

Solutions

  1. Replace the expression with a static literal string or timestamp computed in the caller, e.g. `WHERE StartTime = "2023-01-01T00:00:00Z"`
  2. Evaluate NOW()/UPPER() etc. in application code and inline the resulting literal
  3. Inspect the offending expression printed in the error message
  4. Keep both sides of each comparison a bare column and a quoted literal

Example fix

// before
query := `WHERE StartTime = NOW()`
// after
query := `WHERE StartTime = "2023-09-01T00:00:00Z"`
Defensive patterns

Strategy: validation

Validate before calling

for _, clause := range clauses {
	parts := strings.SplitN(clause, "=", 2)
	if len(parts) == 2 {
		rhs := strings.TrimSpace(parts[1])
		if !strings.HasPrefix(rhs, `"`) && !isNumber(rhs) {
			return fmt.Errorf("filter value must be a literal, got %q", rhs)
		}
	}
}

Try / catch

q, err := parseArchiveQuery(raw)
if err != nil {
	return fmt.Errorf("RHS of filter must be a literal: %w", err)
}

Prevention

When it happens

Trigger: A WHERE clause like `WHERE WorkflowType = UPPER("x")`, `WHERE WorkflowID = (SELECT ...)`, or `WHERE StartTime = NOW()` in a query passed to the s3 archive visibility Query API.

Common situations: Dynamic queries embedding function calls or nested expressions; queries generated from templates expecting SQL-computed values; ported SQL that relies on server-side evaluation.

Related errors


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