neondatabase/neon · warning

Cannot refresh compute configuration in state {:?}

Error message

Cannot refresh compute configuration in state {:?}

What it means

signal_refresh_configuration() only accepts a refresh trigger when the compute is in Running, Failed, or already RefreshConfigurationPending; Init is tolerated (refresh happens later); any other status is rejected with this message. It is a state-machine guard: the HTTP route asked to refresh config while the endpoint is transitioning (e.g. stopping/starting/empty), not a failure of the refresh itself.

Source

Thrown at compute_tools/src/compute.rs:2064

    // applies it.
    pub async fn signal_refresh_configuration(&self) -> Result<()> {
        let states_allowing_configuration_refresh = [
            ComputeStatus::Running,
            ComputeStatus::Failed,
            ComputeStatus::RefreshConfigurationPending,
        ];

        let mut state = self.state.lock().expect("state lock poisoned");
        if states_allowing_configuration_refresh.contains(&state.status) {
            state.status = ComputeStatus::RefreshConfigurationPending;
            self.state_changed.notify_all();
            Ok(())
        } else if state.status == ComputeStatus::Init {
            // If the compute is in Init state, we can't refresh the configuration immediately,
            // but we should be able to do that soon.
            Ok(())
        } else {
            Err(anyhow::anyhow!(
                "Cannot refresh compute configuration in state {:?}",
                state.status
            ))
        }
    }

    // Wrapped this around `pg_ctl reload`, but right now we don't use
    // `pg_ctl` for start / stop.
    #[instrument(skip_all)]
    fn pg_reload_conf(&self) -> Result<()> {
        let pgctl_bin = Path::new(&self.params.pgbin)
            .parent()
            .unwrap()
            .join("pg_ctl");
        Command::new(pgctl_bin)
            .args(["reload", "-D", &self.params.pgdata])
            .output()
            .expect("cannot run pg_ctl process");

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Check the compute status (status endpoint) and wait for Running before requesting a config refresh
  2. If the compute is Failed, a refresh is already allowed - retry and it will be accepted; for other states, let the lifecycle action finish first
  3. If stuck in a transitional status, restart/re-provision the compute and then re-apply configuration

Example fix

// before
compute.signal_refresh_configuration().await?;
// after
if !matches!(status, ComputeStatus::Running | ComputeStatus::Failed) {
    wait_until_status(&compute, |s| s == ComputeStatus::Running).await;
}
compute.signal_refresh_configuration().await?;
Defensive patterns

Strategy: validation

Validate before calling

// Caller-side gate mirroring the state machine
const REFRESHABLE: [ComputeStatus; 3] = [Running, Failed, RefreshConfigurationPending];
if !REFRESHABLE.contains(&current_status) && current_status != Init {
    return Ok(()); // skip the call until the compute settles
}

Type guard

fn can_signal_refresh(status: ComputeStatus) -> bool {
    matches!(status, ComputeStatus::Running | ComputeStatus::Failed | ComputeStatus::RefreshConfigurationPending)
        || status == ComputeStatus::Init
}

Try / catch

// Treat as 'come back later', not as an error worth paging on
match compute.signal_refresh_configuration().await {
    Ok(()) => {}
    Err(e) if e.to_string().contains("Cannot refresh compute configuration") => {
        schedule_retry_after_status_change().await;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling signal_refresh_configuration() while state.status is outside {Running, Failed, RefreshConfigurationPending, Init} - e.g. during StopPending/Stopping/Starting or before the first spec is applied.

Common situations: Control plane retries a stale configuration-refresh request after the endpoint moved to a transitional status; a race between a stop/restart request and a config update; status left in an unexpected state by an earlier error path.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/419d951a08d83a3b. Report an issue: GitHub.