risingwavelabs/risingwave · error · ConnectorError

invalid scan.startup.mode, accept earliest/latest/timestamp

Error message

invalid scan.startup.mode, accept earliest/latest/timestamp

What it means

During Kinesis source construction, `new` matches `scan.startup.mode` against the three accepted values `earliest`, `latest`, and `timestamp`. Any other string falls into the wildcard arm and `bail!`s with this message listing the accepted values.

Solutions

  1. Set `scan.startup.mode` to exactly one of 'earliest', 'latest', or 'timestamp' (lowercase, no spaces).
  2. If coming from Kafka-style configs, replace values like 'earliest_offset'/'latest_offset' with 'earliest'/'latest'.
  3. Remove the option entirely to use the default startup mode.

Example fix

// before
WITH (
  connector = 'kinesis',
  stream_name = 'events',
  scan.startup.mode = 'earliest_offset'
)
// after
WITH (
  connector = 'kinesis',
  stream_name = 'events',
  scan.startup.mode = 'earliest'
)
Defensive patterns

Strategy: validation

Validate before calling

// Validate scan.startup.mode against the allowed set before creating the source
const VALID: [&str; 3] = ["earliest", "latest", "timestamp"];
let mode = props.get("scan.startup.mode").map(|s| s.as_str()).unwrap_or("latest");
if !VALID.contains(&mode) {
    return Err(anyhow!("invalid scan.startup.mode '{mode}', must be one of earliest/latest/timestamp"));
}

Prevention

When it happens

Trigger: Setting WITH option `scan.startup.mode` to a value other than earliest/latest/timestamp, e.g. ' Earliest' (case/space), 'from_timestamp', 'oldest', or a typo like 'ealiest'.

Common situations: Migrating configs from Kafka connector (`scan.startup.mode='earliest_offset'`), copy-paste from other systems where modes are named differently, or manual typos in CREATE SOURCE DDL.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/afbc6da088d4d7d4. Report an issue: GitHub.

Appendix: source

Thrown at src/connector/src/source/kinesis/source/reader.rs:95

        assert!(splits.len() == 1);

        let split = splits.into_iter().next().unwrap();

        let next_offset = match &split.next_offset {
            KinesisOffset::None => match &properties.scan_startup_mode {
                None => KinesisOffset::Earliest,
                Some(mode) => match mode.as_str() {
                    "earliest" => KinesisOffset::Earliest,
                    "latest" => KinesisOffset::Latest,
                    "timestamp" => {
                        if let Some(ts) = &properties.start_timestamp_millis {
                            KinesisOffset::Timestamp(*ts)
                        } else {
                            bail!("scan.startup.timestamp.millis is required");
                        }
                    }
                    _ => {
                        bail!("invalid scan.startup.mode, accept earliest/latest/timestamp")
                    }
                },
            },
            next_offset => next_offset.to_owned(),
        };

        if !matches!(next_offset, KinesisOffset::Timestamp(_))
            && properties.start_timestamp_millis.is_some()
        {
            // cannot bail! here because all new split readers will fail to start if user set 'scan.startup.mode' to 'timestamp'
            tracing::warn!(
                "scan.startup.mode needs to be set to 'timestamp' if you want to start with a specific timestamp, starting shard {} from the beginning",
                split.id()
            );
        }

        let stream_name = properties.common.stream_name.clone();
        let client = properties.common.build_client().await?;

View on GitHub (pinned to 6469eb736d)