risingwavelabs/risingwave · error · anyhow::Error

No offsets provided to inject

Error message

No offsets provided to inject

What it means

Guard in inject_source_offsets: the offsets JSON parsed to an empty map, so there are no split offsets to inject. The unsafe offset-injection operation refuses to run with no data rather than truncating source state for nothing.

Solutions

  1. Provide a non-empty JSON map like '{"0":"offset-123"}' keyed by split id
  2. Verify the offsets variable is populated before running this unsafe command
  3. Use the safe alter-source-properties path if you only meant to update connector properties

Example fix

// before
inject_source_offsets(ctx, id, "{}")
// after
inject_source_offsets(ctx, id, "{\"split-0\":\"kafka-offset-42\"}")
Defensive patterns

Strategy: validation

Validate before calling

let offsets: HashMap<String, String> = serde_json::from_str(&offsets_json)?;
if offsets.is_empty() {
    return Err(anyhow!("offsets must contain at least one split"));
}

Prevention

When it happens

Trigger: Calling the inject-offsets command with '{}' or a JSON string that parses to an empty map.

Common situations: Script variable for offsets left empty; copying the command template without filling offsets.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/ctl/src/cmd_impl/meta/source_props.rs:108

    Ok(())
}

/// Inject specific offsets into source splits.
///
/// WARNING: This is an UNSAFE operation that may cause data duplication or loss!
/// Use with extreme caution and only when you know the exact offsets needed.
pub async fn inject_source_offsets(
    context: &CtlContext,
    source_id: u32,
    offsets_json: String,
) -> Result<()> {
    let meta_client = context.meta_client().await?;

    let offsets: HashMap<String, String> =
        serde_json::from_str(&offsets_json).context("Failed to parse offsets as JSON object")?;

    if offsets.is_empty() {
        return Err(anyhow!("No offsets provided to inject"));
    }

    println!("=== INJECT SOURCE OFFSETS (UNSAFE) ===");
    println!("Source ID: {}", source_id);
    println!("Offsets to inject:");
    for (split_id, offset) in &offsets {
        println!("  {} -> {}", split_id, offset);
    }
    println!();
    println!("WARNING: This is an UNSAFE operation!");
    println!("Injecting incorrect offsets WILL cause data duplication or loss!");
    println!("Make sure you know the exact offsets needed before proceeding.");
    println!();

    let applied_splits = meta_client
        .inject_source_offsets(SourceId::from(source_id), offsets)
        .await?;

View on GitHub (pinned to 6469eb736d)