risingwavelabs/risingwave · error
specify at most one of start_offset or start_snapshot
Error message
specify at most one of start_offset or start_snapshot
What it means
PubSub supports seeking either to a timestamp (start_offset) or to a named snapshot (start_snapshot), but not both at once. The enumerator's SeekTo resolution bails if both properties are provided simultaneously. Exactly one of the two must be set (or neither).
Source
Thrown at src/connector/src/source/google_pubsub/enumerator/client.rs:73
.exists(None)
.await
.context("error checking subscription validity")?
{
bail!("subscription {} does not exist", &sub.id())
}
let seek_to = match (properties.start_offset, properties.start_snapshot) {
(None, None) => None,
(Some(start_offset), None) => {
let ts = start_offset
.parse::<i64>()
.context("error parsing start_offset")
.map(|nanos| Utc.timestamp_nanos(nanos).into())?;
Some(SeekTo::Timestamp(ts))
}
(None, Some(snapshot)) => Some(SeekTo::Snapshot(snapshot)),
(Some(_), Some(_)) => {
bail!("specify at most one of start_offset or start_snapshot")
}
};
if let Some(seek_to) = seek_to {
sub.seek(seek_to, None)
.await
.context("error seeking subscription")?;
}
Ok(Self {
subscription: properties.subscription,
})
}
async fn list_splits(&mut self) -> ConnectorResult<Vec<PubsubSplit>> {
tracing::debug!("enumerating pubsub splits (adaptive mode, returning 1 template split)");
Ok(vec![PubsubSplit {
index: 0,View on GitHub (pinned to 6469eb736d)
Solutions
- Remove `start_snapshot` if you want time-based recovery via `start_offset`.
- Remove `start_offset` if you want snapshot-based recovery via `start_snapshot`.
- Omit both if you want to resume from the subscription's current state (default).
Example fix
-- before WITH (connector = 'google_pubsub', start_offset = '2024-01-01T00:00:00Z', start_snapshot = 'my-snap') -- after (keep only one) WITH (connector = 'google_pubsub', start_offset = '2024-01-01T00:00:00Z')
Defensive patterns
Strategy: validation
Validate before calling
// reject configs specifying both
function pubsubSeekPropsValid(p) {
return !(p.start_offset && p.start_snapshot);
} Type guard
function hasNoConflictingSeek(p) {
return !("start_offset" in p && "start_snapshot" in p);
} Try / catch
if (props.start_offset && props.start_snapshot) {
throw new Error("specify at most one of start_offset or start_snapshot");
} Prevention
- Decide on one recovery strategy (timestamp or snapshot) per source.
- Review the full WITH clause when editing configs incrementally.
- Encode the exclusivity in config validation tooling/CI for source DDL.
When it happens
Trigger: Creating a PubSub source with both `start_offset` and `start_snapshot` specified in the WITH clause, hitting the (Some(_), Some(_)) match arm in PubsubEnumeratorClient::new.
Common situations: Copy-pasting a config template that already had start_snapshot and adding start_offset on top; trying to 'be safe' by specifying both; leftover flags from an incremental config edit.
Related errors
- `{CHANNEL}` and `{CHANNEL_COLUMN}` only one can be set
- credentials must be set if not using the pubsub emulator
- subscription {} does not exist
- pubsub.ack_deadline_seconds must be between 10 and 600
- pubsub.max_outstanding_messages must be greater than 0
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/feeb24b033f7e7c0.
Report an issue: GitHub.