risingwavelabs/risingwave · critical

job {} in database {} has no state table after recovery

Error message

job {} in database {} has no state table after recovery

What it means

validate_database_info collects each job's state tables with their committed epochs and requires at least one entry. If a streaming job ends up with zero state tables after recovery, recovery aborts with this error — a job without any state table cannot be part of a consistent recovery snapshot.

Source

Thrown at src/meta/src/barrier/mod.rs:201

                            "state table {} is not registered to hummock",
                            state_table_id
                        )
                        .into());
                    }
                }
            }
            for (job_id, fragments) in database_jobs {
                let mut committed_epochs =
                    InflightFragmentInfo::existing_table_ids(fragments.values()).map(|table_id| {
                        (
                            table_id,
                            *state_table_committed_epochs
                                .get(&table_id)
                                .expect("checked exist"),
                        )
                    });
                let (first_table, first_epoch) = committed_epochs.next().ok_or_else(|| {
                    anyhow!(
                        "job {} in database {} has no state table after recovery",
                        job_id,
                        database_id
                    )
                })?;
                for (table_id, epoch) in committed_epochs {
                    if epoch != first_epoch {
                        return Err(anyhow!(
                            "job {} in database {} has tables with different table ids. {}:{}, {}:{}",
                            job_id,
                            database_id,
                            first_table,
                            first_epoch,
                            table_id,
                            epoch
                        )
                        .into());
                    }

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Inspect the job's fragments/state tables in metadata; repair or recreate the job so it owns state tables
  2. Drop the zombie job via DROP MATERIALIZED VIEW / DROP SINK if it no longer has data
  3. Retry recovery from an earlier consistent metadata snapshot
  4. File a bug with job_id/database_id; empty-state-table jobs indicate a creation/drop race
Defensive patterns

Strategy: validation

Validate before calling

if job.state_tables().next().is_none() {
    return Err(format!("job {} has no state tables", job_id));
}

Type guard

fn has_state_tables(job: &StreamingJobInfo) -> bool { job.fragments.iter().any(|f| !f.state_table_ids.is_empty()) }

Try / catch

if e.to_string().contains("has no state table after recovery") {
    drop_zombie_job(job_id)?; // or restore from an earlier snapshot and retry
}

Prevention

When it happens

Trigger: Recovery where a streaming job (job_id in database_id) maps to no state tables with committed epochs — empty fragment state_table_ids, or all of its tables filtered out during validation.

Common situations: Corrupted or partially-written job metadata; a job whose tables were all dropped but the job itself remained; recovery logic bugs dropping table entries.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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