risingwavelabs/risingwave · error · MetaError
cannot use a different max parallelism when replacing stream
Error message
cannot use a different max parallelism when replacing streaming job, original: {}, new: {} What it means
Replacing a streaming job requires the new definition to use the same max parallelism as the original job, because parallelism affects fragment/actor layout. The expected original max parallelism supplied does not match the persisted job's value.
Source
Thrown at src/meta/src/controller/streaming_job.rs:1616
if batch_refresh_dep_cnt != 0 {
return Err(MetaError::permission_denied(
"replacing a table with dependent batch refresh materialized views is not supported",
));
}
// 3. check parallelism.
let original_job = StreamingJobModel::find_by_id(id)
.one(&txn)
.await?
.map(ReplaceOriginalJobInfo::from)
.ok_or_else(|| MetaError::catalog_id_not_found(streaming_job.job_type_str(), id))?;
if let Some(max_parallelism) = expected_original_max_parallelism
&& original_job.max_parallelism != max_parallelism as i32
{
// We already override the max parallelism in `StreamFragmentGraph` before entering this function.
// This should not happen in normal cases.
bail!(
"cannot use a different max parallelism \
when replacing streaming job, \
original: {}, new: {}",
original_job.max_parallelism,
max_parallelism
);
}
let parallelism = original_job.resolved_parallelism(specified_parallelism);
let ctx = original_job.stream_context(ctx);
let adaptive_parallelism_strategy = original_job
.adaptive_parallelism_strategy
.as_deref()
.map(|s| parse_strategy(s).expect("strategy should be validated before persisting"));
let resource_type = original_job.resource_type();
let belong_to_oid = Object::find_by_id(id)
.select_only()
.column(object::Column::BelongToOid)View on GitHub (pinned to 6469eb736d)
Solutions
- Use the same MAX PARALLELISM as the original job in the ALTER/replace statement.
- Omit the parallelism override so it defaults to the original job's value.
- Check session/database default parallelism settings that may inject a different value.
- If a parallelism change is genuinely needed, drop and recreate the job instead of replacing.
Example fix
-- before ALTER TABLE mv_orders SET MAX PARALLELISM = 32; -- after (match original parallelism, e.g. 16) ALTER TABLE mv_orders SET MAX PARALLELISM = 16;
Defensive patterns
Strategy: validation
Validate before calling
-- match original parallelism before replace SELECT max_parallelism FROM rw_streaming_jobs WHERE job_id = <original_job_id>; -- then use the same MAX PARALLELISM in the ALTER statement
Try / catch
match replace_streaming_job(..).await {
Err(e) if e.to_string().contains("different max parallelism") => /* retry with the original job's max parallelism */,
other => other?,
} Prevention
- Carry over original max_parallelism in replace requests
- Avoid changing session default parallelism between create and replace
- Drop+recreate if parallelism change is required
When it happens
Trigger: create_job_catalog_for_replace where expected_original_max_parallelism is Some(n) but original_job.max_parallelism != n as i32.
Common situations: Altering a MV/table/sink with a different MAX PARALLELISM than the original; frontend failing to carry over parallelism settings; session default parallelism changed between create and replace.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- invalid parallelism
- old sink {} does not match replacement sink {}
- replace sink into table is not supported
- sink {} is not ready to be replaced
- object {} is not a sink
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/08db34aabed564d7.
Report an issue: GitHub.