temporalio/temporal · error
only one of StartTime or CloseTime can be specified in a que
Error message
only one of StartTime or CloseTime can be specified in a query
What it means
The s3store query parser supports time-range narrowing on exactly one of StartTime or CloseTime per query, because the archive time-window computation needs a single anchor. Parse rejects queries whose WHERE clause includes predicates on both time columns.
Source
Thrown at common/archiver/s3store/query_parser.go:72
func (p *queryParser) Parse(query string) (*parsedQuery, error) {
stmt, err := sqlparser.Parse(fmt.Sprintf(sqlquery.QueryTemplate, query))
if err != nil {
return nil, err
}
whereExpr := stmt.(*sqlparser.Select).Where.Expr
parsedQuery := &parsedQuery{}
if err := p.convertWhereExpr(whereExpr, parsedQuery); err != nil {
return nil, err
}
if parsedQuery.workflowID == nil && parsedQuery.workflowType == nil {
return nil, errors.New("WorkflowId or WorkflowType is required in query")
}
if parsedQuery.workflowID != nil && parsedQuery.workflowType != nil {
return nil, errors.New("only one of WorkflowId or WorkflowType can be specified in a query")
}
if parsedQuery.closeTime != nil && parsedQuery.startTime != nil {
return nil, errors.New("only one of StartTime or CloseTime can be specified in a query")
}
if (parsedQuery.closeTime != nil || parsedQuery.startTime != nil) && parsedQuery.searchPrecision == nil {
return nil, errors.New("SearchPrecision is required when searching for a StartTime or CloseTime")
}
if parsedQuery.closeTime == nil && parsedQuery.startTime == nil && parsedQuery.searchPrecision != nil {
return nil, errors.New("SearchPrecision requires a StartTime or CloseTime")
}
return parsedQuery, nil
}
func (p *queryParser) convertWhereExpr(expr sqlparser.Expr, parsedQuery *parsedQuery) error {
if expr == nil {
return errors.New("where expression is nil")
}
switch expr := expr.(type) {
case *sqlparser.ComparisonExpr:View on GitHub (pinned to bde624efd1)
Solutions
- Keep only one time predicate (StartTime or CloseTime) and rely on SearchPrecision for the scan window.
- Apply the second time bound as post-filtering on returned records in application code.
- Combine the remaining time condition with AND of SearchPrecision (required for time filters).
Example fix
// before
parser.Parse("WorkflowId = 'w1' AND StartTime > '2024-01-01' AND CloseTime < '2024-02-01'")
// after
parser.Parse("WorkflowId = 'w1' AND StartTime > '2024-01-01' AND SearchPrecision = 'Day'") Defensive patterns
Strategy: validation
Validate before calling
hasStart := strings.Contains(query, "StartTime")
hasClose := strings.Contains(query, "CloseTime")
if hasStart && hasClose {
return errors.New("specify only one of StartTime or CloseTime")
} Try / catch
pq, err := parser.Parse(query)
if err != nil {
if strings.Contains(err.Error(), "only one of StartTime or CloseTime") {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
return nil, err
} Prevention
- Build time ranges with a single archival time field plus SearchPrecision.
- Apply the other time bound as an in-memory post-filter on results.
- Reject date-range inputs at the UI layer for archive searches.
When it happens
Trigger: Calling Parse with e.g. "WorkflowId = 'w1' AND StartTime > '...' AND CloseTime < '...'" — both parsedQuery.startTime and parsedQuery.closeTime are non-nil after convertWhereExpr.
Common situations: Users writing standard date-range queries (start AND end bounds) as they would against SQL databases; query builders that always add both start and close time bounds.
Related errors
- WorkflowId or WorkflowType is required in query
- only one of WorkflowId or WorkflowType can be specified in a
- SearchPrecision is required when searching for a StartTime o
- SearchPrecision requires a StartTime or CloseTime
- where expression is nil
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/82ff607c41fd3576.
Report an issue: GitHub.