risingwavelabs/risingwave · error · SinkError::Config

invalid value for `is_exactly_once`: expected `true` or…

Error message

invalid value for `is_exactly_once`: expected `true` or `false`, got `{value}`

What it means

Parser guard in Sink::is_exactly_once for the LanceDB sink: the `is_exactly_once` property, when present, must parse as a boolean literal `true` or `false`. Any other string (e.g. `1`, `yes`, `TRUE` with wrong casing) is rejected with this config error; absent property defaults to true.

Solutions

  1. Set 'is_exactly_once' = 'true' or 'false' (lowercase literals)
  2. Remove the option entirely to accept the default (true)
  3. Check for stray quotes or whitespace around the value

Example fix

// before
WITH ('is_exactly_once' = 'True')
// after
WITH ('is_exactly_once' = 'true')
Defensive patterns

Strategy: validation

Validate before calling

function checkExactlyOnce(v) {
  if (v !== undefined && v !== 'true' && v !== 'false')
    throw new Error(`is_exactly_once must be 'true' or 'false', got '${v}'`);
}

Try / catch

catch (SinkError::Config(e)) if e.contains("is_exactly_once") { fix the WITH clause value to a lowercase boolean literal }

Prevention

When it happens

Trigger: CREATE SINK ... WITH ('is_exactly_once' = 'yes') or any value other than the literal strings 'true'/'false'.

Common situations: Users passing '1'/'0', 'True'/'False' (capitalized), 'yes'/'no', or accidentally quoting the value twice.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/connector/src/sink/lancedb.rs:181

}

impl LanceDbSink {
    pub fn new(config: LanceDbConfig, param: SinkParam) -> Result<Self> {
        Ok(Self { config, param })
    }
}

impl Sink for LanceDbSink {
    type LogSinker = CoordinatedLogSinker<LanceDbSinkWriter>;

    const SINK_NAME: &'static str = LANCEDB_SINK;

    fn is_exactly_once(properties: &BTreeMap<String, String>) -> Result<bool> {
        let Some(value) = properties.get("is_exactly_once") else {
            return Ok(true);
        };
        value.parse::<bool>().map_err(|_| {
            SinkError::Config(anyhow!(
                "invalid value for `is_exactly_once`: expected `true` or `false`, got `{value}`"
            ))
        })
    }

    async fn new_log_sinker(&self, writer_param: SinkWriterParam) -> Result<Self::LogSinker> {
        let inner = LanceDbSinkWriter::new(self.config.clone(), self.param.schema()).await?;

        let commit_checkpoint_interval =
            NonZeroU64::new(self.config.common.commit_checkpoint_interval).expect(
                "commit_checkpoint_interval should be greater than 0, and it should be checked in config validation",
            );

        let writer = CoordinatedLogSinker::new(
            &writer_param,
            self.param.clone(),
            inner,
            commit_checkpoint_interval,

View on GitHub (pinned to 6469eb736d)