risingwavelabs/risingwave · error · SinkError::Config

(serde_json deserialization error)

Error message

(serde_json deserialization error)

What it means

LanceDbConfig::from_btreemap serializes the user's WITH-option map to JSON and deserializes it into LanceDbConfig. A mismatch between provided option keys/types and the struct definition produces a serde error wrapped as SinkError::Config, so the sink cannot be built.

Source

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

#[derive(Clone, Debug, Deserialize, WithOptions)]
pub struct LanceDbConfig {
    #[serde(flatten)]
    pub common: LanceDbCommon,

    pub r#type: String,

    /// Whether to use RisingWave's two-phase commit framework for exactly-once commits.
    /// Defaults to true. Set to false to use single-phase commits.
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub is_exactly_once: Option<bool>,
}

impl LanceDbConfig {
    pub fn from_btreemap(properties: BTreeMap<String, String>) -> Result<Self> {
        let config = serde_json::from_value::<LanceDbConfig>(
            serde_json::to_value(properties).map_err(|e| SinkError::LanceDb(e.into()))?,
        )
        .map_err(|e| SinkError::Config(anyhow!(e)))?;
        Ok(config)
    }
}

// ---------------------------------------------------------------------------
// Sink
// ---------------------------------------------------------------------------

#[derive(Debug)]
pub struct LanceDbSink {
    pub config: LanceDbConfig,
    param: SinkParam,
}

impl EnforceSecret for LanceDbSink {
    fn enforce_secret<'a>(
        _prop_iter: impl Iterator<Item = &'a str>,
    ) -> crate::error::ConnectorResult<()> {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Read the serde error message; it names the offending field and expected type
  2. Fix the misspelled or mistyped option in the WITH clause
  3. Only use documented options: lancedb.uri, lancedb.table and common sink options
  4. Remove options not defined on LanceDbConfig

Example fix

// before
CREATE SINK s INTO lancedb WITH (
  'connector' = 'lancedb',
  'lancedb.url' = '/tmp/lancedb'
);
// after
CREATE SINK s INTO lancedb WITH (
  'connector' = 'lancedb',
  'lancedb.uri' = '/tmp/lancedb',
  'lancedb.table' = 'my_table'
);
Defensive patterns

Strategy: validation

Validate before calling

const REQUIRED = ['connector','lancedb.uri','lancedb.table'];
function validateProps(props) {
  for (const k of REQUIRED) if (!(k in props)) throw new Error(`missing ${k}`);
  const allowed = new Set([...REQUIRED, 'type', 'is_exactly_once', 'commit_checkpoint_interval']);
  for (const k of Object.keys(props)) if (!allowed.has(k)) throw new Error(`unknown option ${k}`);
}

Try / catch

try { const cfg = LanceDbConfig.from_btreemap(props); } catch (e) { logConfigError(e, props); throw; }

Prevention

When it happens

Trigger: CREATE SINK ... WITH (...) where an option is misspelled, an unexpected/unknown key is given, or a field's value cannot deserialize into the declared type (e.g., a non-numeric string for a numeric field).

Common situations: Typos in lancedb.uri / lancedb.table keys, leftover options from another connector, quoting issues in SQL string literals, or copy-pasted options with wrong types.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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