Observed behavior
When a new source with OptStartTime is added to a stream that already contains
newer messages (e.g. an aggregate stream sourcing from several origins), the
source's start time is silently clamped forward to the destination stream's
LastTime.
Any message on the origin whose timestamp is after the configured
OptStartTime but before the destination's current LastTime is never
sourced — it is permanently skipped, not just delayed.
The clamp is in setupSourceConsumer/trySetupSourceConsumer (server/stream.go):
if !state.LastTime.IsZero() && ssi.OptStartTime.Before(state.LastTime) {
req.Config.OptStartTime = &state.LastTime
}
Using OptStartSeq instead of OptStartTime avoids the clamp entirely and
delivers the messages.
Expected behavior
A source configured with OptStartTime = T should deliver all origin messages
with timestamp >= T, as documented ("Any messages that are equal to or greater
than the start time will be included"), regardless of how many newer messages
the destination stream already holds.
At minimum, if the forward-clamp to the destination LastTime is intentional
(it appears to originate from the restart-dedup fix in #3559 / #3606), it should
be documented, since it can cause silent data loss for a freshly added source.
Server and client version
Reproduced on nats-server v2.11.6.
The relevant code (trySetupSourceConsumer in server/stream.go) is byte-identical
through v2.14.1 and v2.14.2 (latest), so it reproduces on the latest release.
Host environment
Not environment-specific. Observed with an embedded nats-server run via go test
on macOS (arm64) and Linux (arm64) containers. Single server, file storage.
Steps to reproduce
No response
Observed behavior
When a new source with
OptStartTimeis added to a stream that already containsnewer messages (e.g. an aggregate stream sourcing from several origins), the
source's start time is silently clamped forward to the destination stream's
LastTime.Any message on the origin whose timestamp is after the configured
OptStartTimebut before the destination's currentLastTimeis neversourced — it is permanently skipped, not just delayed.
The clamp is in
setupSourceConsumer/trySetupSourceConsumer(server/stream.go):if !state.LastTime.IsZero() && ssi.OptStartTime.Before(state.LastTime) {
req.Config.OptStartTime = &state.LastTime
}
Using
OptStartSeqinstead ofOptStartTimeavoids the clamp entirely anddelivers the messages.
Expected behavior
A source configured with
OptStartTime = Tshould deliver all origin messageswith timestamp >= T, as documented ("Any messages that are equal to or greater
than the start time will be included"), regardless of how many newer messages
the destination stream already holds.
At minimum, if the forward-clamp to the destination
LastTimeis intentional(it appears to originate from the restart-dedup fix in #3559 / #3606), it should
be documented, since it can cause silent data loss for a freshly added source.
Server and client version
Reproduced on nats-server v2.11.6.
The relevant code (
trySetupSourceConsumerin server/stream.go) is byte-identicalthrough v2.14.1 and v2.14.2 (latest), so it reproduces on the latest release.
Host environment
Not environment-specific. Observed with an embedded nats-server run via
go teston macOS (arm64) and Linux (arm64) containers. Single server, file storage.
Steps to reproduce
No response