linera-io/linera-protocol · error

expected query to start with 'query', got: {s}

Error message

expected query to start with 'query', got: {s}

What it means

A --allow-subscription value did not start with the literal keyword `query`. parse_allowed_subscription only accepts strings of the shape `query Name { ... }` — it strips the prefix "query", requires whitespace right after it, then extracts the operation name used to register the subscription.

Source

Thrown at linera-service/src/query_subscription.rs:33

use tokio::sync::watch;
use tokio_util::sync::CancellationToken;
use tracing::{debug, warn};

/// A named GraphQL query string registered at startup via `--allow-subscription`.
#[derive(Clone, Debug)]
pub struct RegisteredQuery {
    /// The operation name used to refer to the query.
    pub name: String,
    /// The full GraphQL query string.
    pub query: String,
}

/// Parses a GraphQL query string like `query Name { ... }` and extracts the operation name.
pub fn parse_allowed_subscription(s: &str) -> anyhow::Result<RegisteredQuery> {
    let trimmed = s.trim();
    let rest = trimmed
        .strip_prefix("query")
        .ok_or_else(|| anyhow::anyhow!("expected query to start with 'query', got: {s}"))?;
    // The character right after "query" must be whitespace (not part of a longer word).
    anyhow::ensure!(
        rest.starts_with(char::is_whitespace),
        "expected whitespace after 'query' keyword"
    );
    let rest = rest.trim_start();
    // Extract the operation name: sequence of alphanumeric/underscore chars.
    let name = rest
        .split(|c: char| !c.is_alphanumeric() && c != '_')
        .next()
        .unwrap_or_default();
    anyhow::ensure!(
        !name.is_empty(),
        "expected an operation name after 'query', e.g. 'query MyQuery {{ ... }}'"
    );
    Ok(RegisteredQuery {
        name: name.to_string(),
        query: trimmed.to_string(),

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Prefix the document with the keyword and a name: `query Transfers { transfers { amount } }`.
  2. Do not use `subscription` documents — this flag registers polled queries, and only the `query` keyword is accepted.
  3. Keep whitespace between `query` and the operation name.
  4. Pick a stable operation name; it is the key used for later --subscription-ttl Name=Secs settings.

Example fix

# before
--allow-subscription 'subscription Transfers { transfers { amount } }'

# after
--allow-subscription 'query Transfers { transfers { amount } }'
Defensive patterns

Strategy: validation

Validate before calling

let t = s.trim();
ensure!(
    t == "query" || t.starts_with("query ") || t.starts_with("query\n"),
    "--allow-subscription must start with the 'query' keyword, e.g. 'query Name {{ ... }}'"
);

Type guard

fn is_query_operation(s: &str) -> bool {
    let t = s.trim();
    match t.strip_prefix("query") {
        Some(rest) => rest.is_empty() || rest.starts(char::is_whitespace),
        None => false,
    }
}

Prevention

When it happens

Trigger: Passing a `subscription ...` document, a bare query body `{ transfers { amount } }` with no keyword, or a keyword glued to the name (`queryTransfers`) — the last one instead trips the whitespace check, but a missing/other keyword trips this error.

Common situations: Registering actual GraphQL subscriptions (not supported here — only named queries); copy-pasting query bodies from GraphQL playgrounds that omit the keyword; assuming the parser accepts shorthand queries.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/c1767fee9069784e. Report an issue: GitHub.