temporalio/temporal · error
missing or invalid query
Error message
missing or invalid query
What it means
handleListMatchingTimesQuery handles the ListScheduleMatchingTimes workflow query. It requires a non-nil request carrying both StartTime and EndTime; if the query input is missing or lacks the time range, it returns this error. A nil s.cspec additionally indicates the schedule itself is invalid and yields a different error.
Source
Thrown at service/worker/scheduler/workflow.go:1167
return out
}
func (s *scheduler) handleDescribeQuery() (*schedulespb.DescribeResponse, error) {
// this is a query handler, don't modify s.Info directly
infoCopy := common.CloneProto(s.Info)
infoCopy.FutureActionTimes = s.getFutureActionTimes(false, s.tweakables.FutureActionCount)
infoCopy.BufferSize = int64(len(s.State.BufferedStarts))
return &schedulespb.DescribeResponse{
Schedule: s.Schedule,
Info: infoCopy,
ConflictToken: s.State.ConflictToken,
}, nil
}
func (s *scheduler) handleListMatchingTimesQuery(req *workflowservice.ListScheduleMatchingTimesRequest) (*workflowservice.ListScheduleMatchingTimesResponse, error) {
if req == nil || req.StartTime == nil || req.EndTime == nil {
return nil, errors.New("missing or invalid query")
}
if s.cspec == nil {
return nil, fmt.Errorf("invalid schedule: %s", s.Info.InvalidScheduleError)
}
var out []*timestamppb.Timestamp
t1 := timestamp.TimeValue(req.StartTime)
for range maxListMatchingTimesCount {
// don't need to call GetNextTime in SideEffect because this is just a query
res, err := s.cspec.GetNextTime(s.jitterSeed(), t1)
if err != nil {
// An over-excluded spec won't resolve until it's edited, so return a
// non-retryable code: retrying would just re-burn the compute bound each call.
return nil, ErrScheduleSpecLimitHit
}
t1 = res.Next
if t1.IsZero() || t1.After(timestamp.TimeValue(req.EndTime)) {
breakView on GitHub (pinned to bde624efd1)
Solutions
- Provide both StartTime and EndTime in the ListScheduleMatchingTimesRequest, e.g. timestamppb.New(time.Now()) and timestamppb.New(time.Now().Add(7*24*time.Hour)).
- Use the SDK's Schedule.ListTimes helper instead of hand-building the query payload so required fields are populated.
- Check the CLI command arguments — ensure the time range flags are actually passed.
- If this appears despite valid input, verify the schedule is not invalid (a nil cspec produces 'invalid schedule: ...' instead).
Example fix
// before
resp, err := scheduleHandle.query(ctx, "list-schedule-matching-times", nil)
// after
req := &workflowservice.ListScheduleMatchingTimesRequest{
StartTime: timestamppb.New(start),
EndTime: timestamppb.New(end),
}
resp, err := scheduleHandle.ListMatchingTimes(ctx, req) Defensive patterns
Strategy: validation
Validate before calling
func validMatchingTimesReq(req *workflowservice.ListScheduleMatchingTimesRequest) bool {
return req != nil && req.StartTime != nil && req.EndTime != nil
} Type guard
func hasTimeRange(req *workflowservice.ListScheduleMatchingTimesRequest) bool {
return req != nil && req.GetStartTime() != nil && req.GetEndTime() != nil
} Prevention
- Always pass both start and end times when querying matching times
- Use SDK Schedule helpers instead of hand-built query payloads
- Add required-flag checks to CLI commands that issue this query
- Return a clear client-side error when the time range is absent
When it happens
Trigger: Issuing a ListScheduleMatchingExecutions / ListScheduleMatchingTimes query against a schedule workflow with a nil request, or with StartTime or EndTime unset (nil protobuf timestamps).
Common situations: CLI/SDK calls where start/end flags were not provided; programmatic query invocation constructing the request struct but forgetting timestamppb fields; tooling sending an empty query payload to the workflow.
Related errors
- out of range
- conflicting timezone names
- ${errs}
- CronString has time zone but missing fields
- CronString does not have 5-7 fields
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/84a7240897dbccd3.
Report an issue: GitHub.