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

  1. Use the same MAX PARALLELISM as the original job in the ALTER/replace statement.
  2. Omit the parallelism override so it defaults to the original job's value.
  3. Check session/database default parallelism settings that may inject a different value.
  4. 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

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


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