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

The NATS source reader only accepts 'earliest', 'latest', or 'timestamp' as scan.startup.mode; any other value is rejected at reader construction. This guards against typos and unsupported startup strategies reaching the consumer.

Source

Thrown at src/connector/src/source/nats/source/reader.rs:78

        // We guarantee the split num always align with parallelism
        assert_eq!(splits.len(), 1);
        let split = splits.into_iter().next().unwrap();
        let split_id = split.split_id;
        let start_position = match &split.start_sequence {
            NatsOffset::None => match &properties.scan_startup_mode {
                None => NatsOffset::Earliest,
                Some(mode) => match mode.as_str() {
                    "latest" => NatsOffset::Latest,
                    "earliest" => NatsOffset::Earliest,
                    "timestamp" | "timestamp_millis" /* backward-compat */ => {
                        if let Some(ts) = &properties.start_timestamp_millis {
                            NatsOffset::Timestamp(*ts)
                        } else {
                            bail!("scan.startup.timestamp.millis is required");
                        }
                    }
                    _ => {
                        bail!("invalid scan.startup.mode, accept earliest/latest/timestamp")
                    }
                },
            },
            // We have record on this Nats Split, contains the last seen offset (seq id) or reply subject
            // We do not use the seq id as start position anymore,
            // but just let the reader load from durable consumer on broker.
            start_position => start_position.to_owned(),
        };

        let mut config = consumer::pull::Config {
            ..Default::default()
        };
        properties.set_config(&mut config)?;

        let (consumer, client) = properties
            .common
            .build_consumer(
                properties.stream.clone(),

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Set scan.startup.mode to exactly one of 'earliest', 'latest', or 'timestamp' (lowercase).
  2. If migrating from Kafka defaults, use 'earliest' or 'latest' instead of Kafka-specific names.
  3. For timestamp mode, also supply scan.startup.timestamp.millis.

Example fix

// before
WITH (connector = 'nats', scan.startup.mode = 'beginning')
// after
WITH (connector = 'nats', scan.startup.mode = 'earliest')
Defensive patterns

Strategy: validation

Validate before calling

const VALID: [&str; 3] = ["earliest", "latest", "timestamp"];
if let Some(mode) = props.get("scan.startup.mode") {
    if !VALID.contains(&mode.as_str()) && mode != "timestamp_millis" {
        return Err(format!("invalid scan.startup.mode: {mode}"));
    }
}

Type guard

fn is_valid_nats_startup_mode(mode: &str) -> bool {
    matches!(mode, "earliest" | "latest" | "timestamp" | "timestamp_millis")
}

Try / catch

match source.create().await {
    Err(e) if e.to_string().contains("invalid scan.startup.mode") => eprintln!("use earliest/latest/timestamp"),
    other => other,
}

Prevention

When it happens

Trigger: Creating a NATS source with `scan.startup.mode` set to a value outside {earliest, latest, timestamp, timestamp_millis} — e.g. 'beginning', 'default', 'EARLIEST', or 'from_timestamp'.

Common situations: Copying Kafka-style startup options ('earliest_offset'/'latest_offset') into a NATS source; case-sensitivity mistakes; typos like 'earlies'.

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/c432df2bae9a8653. Report an issue: GitHub.