From e936a58ea7467671b6c25aab07505bbb96d61c57 Mon Sep 17 00:00:00 2001 From: Ford Date: Mon, 15 Jun 2026 16:09:25 -0700 Subject: [PATCH] graphql, graph: Error on _logs query when log store disabled Previously, querying `_logs` against an indexer with no log store configured returned empty results, indistinguishable from a subgraph that produced no logs. Return a NotSupported error instead so clients can tell the feature is not enabled. Also remove the unused LogStoreError::Unavailable variant. --- graph/src/components/log_store/mod.rs | 3 --- graphql/src/execution/execution.rs | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/graph/src/components/log_store/mod.rs b/graph/src/components/log_store/mod.rs index b1d8dde2f16..a1db6b6aed5 100644 --- a/graph/src/components/log_store/mod.rs +++ b/graph/src/components/log_store/mod.rs @@ -17,9 +17,6 @@ pub enum LogStoreError { #[error("log store query failed: {0}")] QueryFailed(#[from] anyhow::Error), - #[error("log store is unavailable")] - Unavailable, - #[error("log store initialization failed: {0}")] InitializationFailed(anyhow::Error), diff --git a/graphql/src/execution/execution.rs b/graphql/src/execution/execution.rs index b2a7136f75f..c3d116e6c64 100644 --- a/graphql/src/execution/execution.rs +++ b/graphql/src/execution/execution.rs @@ -303,6 +303,17 @@ pub(crate) async fn execute_root_selection_set_uncached( )]); } + // If a client requests `_logs` but this indexer has no log store + // configured, return an error rather than silently returning empty + // results, which would otherwise be indistinguishable from a subgraph that + // genuinely produced no logs. Checked before prefetch/introspection so we + // don't do that work only to error out. + if !logs_fields.is_empty() && !ctx.log_store.is_available() { + return Err(vec![QueryExecutionError::NotSupported( + "the `_logs` query is not enabled on this indexer".to_string(), + )]); + } + // If we are getting regular data, prefetch it from the database let (mut values, trace) = if data_set.is_empty() && meta_items.is_empty() { (Object::default(), Trace::None)