risingwavelabs/risingwave · error · SinkError::Config
Please specific either
Error message
Please specific either `{STREAM}` or `{STREAM_COLUMN}`. They are mutually exclusive options. What it means
For `value type = 'stream'`, the Redis sink requires exactly one of two mutually exclusive options: a fixed stream name (`stream`) or a per-row stream name column (`stream column`). `validate` fails when neither is set, or when both are set at once.
Solutions
- Provide exactly one: either `stream = '<fixed stream name>'` or `stream column = '<varchar column>'`.
- Remove the duplicate option if both are present.
- Verify option key spelling (`stream`, `stream column`) so the intended one is actually parsed.
Example fix
// before WITH (connector='redis', value type='stream', stream='alerts', stream column='topic') // after WITH (connector='redis', value type='stream', stream column='topic')
Defensive patterns
Strategy: validation
Validate before calling
const n = ['stream', 'stream column'].filter(k => k in opts).length;
if (opts['value type'] === 'stream' && n !== 1) throw new Error('set exactly one of stream / stream column'); Try / catch
try { await createSink(cfg); } catch (e) { if (/mutually exclusive/.test(String(e))) { delete cfg.stream; await createSink(cfg); } else throw e; } Prevention
- Build sink configs via a helper that enforces one-of constraints
- When migrating configs, diff old vs new options to catch leftovers
- Check for typos that make neither option actually present
When it happens
Trigger: Create a sink with `value type='stream'` and: (a) no `stream`/`stream column` option at all, or (b) both `stream='name'` and `stream column='col'` supplied.
Common situations: Users migrating configs add `stream` while forgetting to remove `stream column`, or forget that stream sinks need a target unlike the pubsub flow; typos like `stream_name` leave neither option visible.
Related errors
- ` ` must be set to `varchar
- `enable_pk_index` cannot be true when `force_append_only`…
- ` ` must be set to `varchar
- auth.method=key_pair_file must not set `password`
- auth.method=key_pair_file must not set `private_key_pem`
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/ef42db6df07d27a8.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/sink/redis.rs:457
}
let value_format =
self.format_desc.options.get(VALUE_FORMAT).ok_or_else(|| {
SinkError::Config(anyhow!("Cannot find `{VALUE_FORMAT}`"))
})?;
TemplateStringEncoder::check_string_format(value_format, &all_map)?;
}
Some(REDIS_VALUE_TYPE_STREAM) => {
tracing::error!("test:for bug");
risingwave_common::license::Feature::RedisSinkStream
.check_available()
.map_err(|e| anyhow::anyhow!(e))?;
let stream = self.format_desc.options.get(STREAM);
let stream_column = self.format_desc.options.get(STREAM_COLUMN);
if (stream.is_none() && stream_column.is_none())
|| (stream.is_some() && stream_column.is_some())
{
return Err(SinkError::Config(anyhow!(
"Please specific either `{STREAM}` or `{STREAM_COLUMN}`. They are mutually exclusive options."
)));
}
if let Some(stream_column) = stream_column
&& let Some(stream_column_type) = all_map.get(stream_column)
&& (stream_column_type != &DataType::Varchar)
{
return Err(SinkError::Config(anyhow!(
"`{STREAM_COLUMN}` must be set to `varchar`"
)));
}
let value_format =
self.format_desc.options.get(VALUE_FORMAT).ok_or_else(|| {
SinkError::Config(anyhow!("Cannot find `{VALUE_FORMAT}`"))
})?;
let key_format = self.format_desc.options.get(KEY_FORMAT).ok_or_else(|| {View on GitHub (pinned to 6469eb736d)