nautechsystems/nautilus_trader · error
Cannot execute time-range RequestJoin without a child window
Error message
Cannot execute time-range RequestJoin without a child window
What it means
A time-range RequestJoin must be able to yield an initial child window; if DefaultTimeRangeGenerator.can_yield_initial_window() is false, there is no child interval to fan out to and execution aborts. This prevents joining against an empty/degenerate time-range pipeline.
Source
Thrown at crates/data/src/engine/time_range.rs:94
| RequestCommand::BookDepth(_)
| RequestCommand::Join(_)
)
}
impl DataEngine {
pub(super) fn execute_time_range_pipeline_request(
&mut self,
req: RequestCommand,
) -> anyhow::Result<()> {
let request_id = *req.request_id();
let (start_dt, end_dt, start_ns, end_ns) = self.bound_time_range_pipeline_dates(&req)?;
let ts_init = self.clock.borrow().timestamp_ns();
let parent =
time_range_parent_request_with_dates(req, Some(start_dt), Some(end_dt), ts_init);
let response_client_id = self.time_range_pipeline_response_client_id(&parent);
let generator = DefaultTimeRangeGenerator::new(request_params(&parent), start_ns, end_ns)?;
if matches!(parent, RequestCommand::Join(_)) && !generator.can_yield_initial_window() {
anyhow::bail!("Cannot execute time-range RequestJoin without a child window");
}
self.time_range_pipeline_requests.insert(
request_id,
TimeRangePipelineState {
parent,
generator,
start_ns,
end_ns,
response_client_id,
data_count: 0,
last_response: None,
},
);
if let Err(e) = self.dispatch_next_time_range_pipeline_request(request_id, None) {
self.abort_time_range_pipeline(request_id);
return Err(e);View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the Join request's start_ns < end_ns so at least one window exists
- Provide valid durations_seconds (positive, at least 1ns) in the request params
- If a Join with no child window is legitimately possible, handle the empty case before calling execute_time_range_pipeline_request
Example fix
// before
let params = Params::from([("durations_seconds", json!([0]))]); // no valid window
// after
let params = Params::from([("durations_seconds", json!([1.0]))]);
assert!(start_ns < end_ns); Defensive patterns
Strategy: validation
Validate before calling
assert!(start_ns < end_ns, "Join window must be non-empty"); assert!(durations.iter().all(|d| d.is_none() || *d >= 1.0));
Prevention
- Validate Join request windows and durations_seconds before execute_request
- Never use 0 or sub-nanosecond values as durations; use null for 'none'
- Test Join configs with edge-case windows (start==end) in CI
When it happens
Trigger: Executing a time-range pipeline request whose parent is RequestCommand::Join while its configured windows (start/end and durations_seconds) produce no initial window — e.g. a zero-width or inverted window, or durations that filter out every candidate interval.
Common situations: Configuring a Join request with start == end; providing durations_seconds values that discard all windows; passing wrong params so the generator has no intervals to emit at t0.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- No active time-range pipeline for {parent_id}
- start was > end
- Invalid config type for AxExecutionClientFactory. Expected A
- Instrument not found in cache: {symbol}
- Failed to start execution intent reservation: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/25231cb81fb49e9f.
Report an issue: GitHub.