neondatabase/neon · error

file cache size query returned no rows

Error message

file cache size query returned no rows

What it means

`FileCache::get_file_cache_size` runs `SELECT pg_size_bytes(current_setting('neon.file_cache_size_limit'))` via `query_with_retry` and expects exactly one row containing the current cache size in bytes. Postgres returns a row for this scalar SELECT even when the setting is empty, so a zero-row result means the query path itself is broken (severe connection anomaly or a misbehaving client), not a missing setting.

Source

Thrown at libs/vm_monitor/src/filecache.rs:239

                    .await
                    .context("failed to execute query a second time")
            }
        }
    }

    /// Get the current size of the file cache.
    #[tracing::instrument(skip_all)]
    pub async fn get_file_cache_size(&mut self) -> anyhow::Result<u64> {
        self.query_with_retry(
            // The file cache GUC variable is in MiB, but the conversion with
            // pg_size_bytes means that the end result we get is in bytes.
            "SELECT pg_size_bytes(current_setting('neon.file_cache_size_limit'));",
            &[],
        )
        .await
        .context("failed to query pg for file cache size")?
        .first()
        .ok_or_else(|| anyhow!("file cache size query returned no rows"))?
        // pg_size_bytes returns a bigint which is the same as an i64.
        .try_get::<_, i64>(0)
        // Since the size of the table is not negative, the cast is sound.
        .map(|bytes| bytes as u64)
        .context("failed to extract file cache size from query result")
    }

    /// Attempt to set the file cache size, returning the size it was actually
    /// set to.
    #[tracing::instrument(skip_all, fields(%num_bytes))]
    pub async fn set_file_cache_size(&mut self, num_bytes: u64) -> anyhow::Result<u64> {
        let max_bytes = self
            // The file cache GUC variable is in MiB, but the conversion with pg_size_bytes
            // means that the end result we get is in bytes.
            .query_with_retry(
                "SELECT pg_size_bytes(current_setting('neon.max_file_cache_size'));",
                &[],
            )

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Check vm-monitor to compute-node postgres connection health and retry the operation
  2. If in a test, make the mocked query client return one row for `SELECT pg_size_bytes(current_setting('neon.file_cache_size_limit'))`
  3. Inspect logs for the preceding `failed to query pg for file cache size` context to find the underlying connection error
  4. Verify you are connected to a Neon compute node where the `neon.file_cache_size_limit` GUC exists
Defensive patterns

Strategy: retry

Try / catch

match filecache.get_file_cache_size().await {
    Ok(size) => { /* use size */ }
    Err(e) if e.to_string().contains("no rows") => {
        // scalar SELECT returning nothing is a transport anomaly: reconnect and retry
        reconnect().await?;
        let size = filecache.get_file_cache_size().await?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `get_file_cache_size()` when the underlying postgres connection returns zero rows for the scalar SELECT — a degraded pool connection, a test-mocked sqlx client that forgot to enqueue a row for this statement, or a proxy mangling result sets.

Common situations: Unit tests with mocked SQL clients missing row fixtures; flaky connectivity between vm-monitor and the compute node's postgres; running the monitor against a non-Neon postgres or through a misconfigured pgbouncer/proxy.

Related errors


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