risingwavelabs/risingwave · error · ConnectorError

No allow_alter_on_fly fields registered for sink

Error message

No allow_alter_on_fly fields registered for sink: {sink_name}

What it means

Raised when the sink name resolves (or is JdbcSink) but neither CONNECTION_ALLOW_ALTER_ON_FLY_FIELDS nor SINK_ALLOW_ALTER_ON_FLY_FIELDS contains an entry for it — no fields registered as alterable on the fly for this sink.

Solutions

  1. Re-run the code generation that builds SINK_ALLOW_ALTER_ON_FLY_FIELDS.
  2. Add allow_alter_on_fly fields to the sink definition and regenerate if it should support them.
  3. Bypass this validation for sinks with no registered fields.

Example fix

// before
check_sink_allow_alter_on_fly_fields(sink, fields)?;
// after
match sink_allow_alter_fields(sink) {
    Some(_) => check_sink_allow_alter_on_fly_fields(sink, fields)?,
    None => {} // sink does not support on-the-fly alterations
}
Defensive patterns

Strategy: type-guard

Validate before calling

fn sink_has_alter_fields(name: &str) -> bool {
    if name == JdbcSink::SINK_NAME {
        return CONNECTION_ALLOW_ALTER_ON_FLY_FIELDS.get(JdbcSink::SINK_NAME).is_some();
    }
    sink_properties::sink_name_to_config_type_name(name)
        .and_then(|t| SINK_ALLOW_ALTER_ON_FLY_FIELDS.get(t))
        .is_some()
}

Try / catch

if sink_has_alter_fields(sink) {
    check_sink_allow_alter_on_fly_fields(sink, fields)?;
}

Prevention

When it happens

Trigger: Calling check_sink_allow_alter_on_fly_fields with a valid sink name lacking a generated allow-list entry (generator not run, stale generated code, or sink intentionally has none).

Common situations: Newly added sink without regenerated maps; cached build missing updated generated code; calling the check for a sink that does not support on-the-fly field alterations.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at src/connector/src/with_options_test.rs:865

) -> crate::error::ConnectorResult<()> {{
    // TODO(#24846): JDBC sink currently uses `()` as sink config type in `for_all_sinks!`,
    // so it cannot have an isolated key in `SINK_ALLOW_ALTER_ON_FLY_FIELDS`.
    // Reuse the JDBC entry in `CONNECTION_ALLOW_ALTER_ON_FLY_FIELDS` for now.
    // TODO(#24846): remove this special case after JDBC sink has a dedicated config type
    // and allow-alter fields are generated directly into `SINK_ALLOW_ALTER_ON_FLY_FIELDS`.
    let allowed_fields = if sink_name == JdbcSink::SINK_NAME {{
        CONNECTION_ALLOW_ALTER_ON_FLY_FIELDS.get(JdbcSink::SINK_NAME)
    }} else {{
        // Convert sink name to the type name key
        let Some(type_name) = sink_properties::sink_name_to_config_type_name(sink_name) else {{
            return Err(ConnectorError::from(anyhow::anyhow!(
                "Unknown sink connector: {{sink_name}}"
            )));
        }};
        SINK_ALLOW_ALTER_ON_FLY_FIELDS.get(type_name)
    }};
    let Some(allowed_fields) = allowed_fields else {{
        return Err(ConnectorError::from(anyhow::anyhow!(
            "No allow_alter_on_fly fields registered for sink: {{sink_name}}"
        )));
    }};
    for field in fields {{
        if !allowed_fields.contains(field) {{
            return Err(ConnectorError::from(anyhow::anyhow!(
                "Field '{{field}}' is not allowed to be altered on the fly for sink: {{sink_name}}"
            )));
        }}
    }}
    Ok(())
}}
"#,
        source_entries = source_entries,
        sink_entries = sink_entries
    )
}

View on GitHub (pinned to 6469eb736d)