{"record":{"id":"c7fab6ba0f057a50","repo":"linera-io/linera-protocol","slug":"expected-an-operation-name-after-query-e-g-qu","errorCode":null,"errorMessage":"expected an operation name after 'query', e.g. 'query MyQuery {{ ... }}'","messagePattern":"expected an operation name after 'query', e\\.g\\. 'query MyQuery (.+?)\\}'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-service/src/query_subscription.rs","lineNumber":45,"sourceCode":"\n/// Parses a GraphQL query string like `query Name { ... }` and extracts the operation name.\npub fn parse_allowed_subscription(s: &str) -> anyhow::Result<RegisteredQuery> {\n    let trimmed = s.trim();\n    let rest = trimmed\n        .strip_prefix(\"query\")\n        .ok_or_else(|| anyhow::anyhow!(\"expected query to start with 'query', got: {s}\"))?;\n    // The character right after \"query\" must be whitespace (not part of a longer word).\n    anyhow::ensure!(\n        rest.starts_with(char::is_whitespace),\n        \"expected whitespace after 'query' keyword\"\n    );\n    let rest = rest.trim_start();\n    // Extract the operation name: sequence of alphanumeric/underscore chars.\n    let name = rest\n        .split(|c: char| !c.is_alphanumeric() && c != '_')\n        .next()\n        .unwrap_or_default();\n    anyhow::ensure!(\n        !name.is_empty(),\n        \"expected an operation name after 'query', e.g. 'query MyQuery {{ ... }}'\"\n    );\n    Ok(RegisteredQuery {\n        name: name.to_string(),\n        query: trimmed.to_string(),\n    })\n}\n\n/// Parses a `Name=Secs` string into a query name and TTL in seconds.\npub fn parse_subscription_ttl(s: &str) -> Result<(String, u64), String> {\n    let (name, secs) = s\n        .split_once('=')\n        .ok_or_else(|| format!(\"expected format Name=Secs, got: {s}\"))?;\n    let secs: u64 = secs\n        .parse()\n        .map_err(|e| format!(\"invalid seconds value '{secs}': {e}\"))?;\n    Ok((name.to_string(), secs))","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-service/src/query_subscription.rs#L27-L63","documentation":"After consuming 'query' plus whitespace, parse_allowed_subscription extracts the leading alphanumeric/underscore run as the operation name; the name is the key clients later use to reference this subscription. This error fires when that run is empty — i.e. the text immediately after 'query ' is punctuation such as '{', ':' or end-of-string, so no name exists to register the query under.","triggerScenarios":"Passing an anonymous GraphQL operation via --allow-subscription, e.g. 'query { transfers { id } }', or something degenerate like 'query :' or 'query '. Parsing happens at node startup inside run(), so the process exits immediately.","commonSituations":"Anonymous queries are legal GraphQL and most clients accept them, so users paste a working query from graphiql/curl only to have the node reject it; also truncated arguments cut off by shell word-splitting.","solutions":["Name the operation: 'query { transfers { id } }' becomes 'query Transfers { transfers { id } }'","Make sure the whole query string is one shell argument (quote it) so the name and body are not lost","Use the same name later in --subscription-ttl entries and in subscription requests, since the extracted name is the registry key"],"exampleFix":"# before\n--allow-subscription 'query { transfers { id } }'\n# after\n--allow-subscription 'query Transfers { transfers { id } }'","handlingStrategy":"validation","validationCode":"// Rust: require a non-empty name after 'query'\nfn subscription_has_name(s: &str) -> bool {\n    let t = s.trim();\n    let Some(rest) = t.strip_prefix(\"query\") else { return false };\n    if !rest.starts_with(char::is_whitespace) { return false; }\n    let rest = rest.trim_start();\n    let name = rest.split(|c: char| !c.is_alphanumeric() && c != '_').next().unwrap_or_default();\n    !name.is_empty()\n}","typeGuard":"fn has_named_query_operation(s: &str) -> bool { subscription_has_name(s) }","tryCatchPattern":"if let Err(e) = parse_allowed_subscription(&arg) {\n    log::warn!(\"skipping subscription {arg:?}: {e:#}\");\n    failures.push(arg);\n}","preventionTips":["Standardize on named GraphQL operations in your project's query files","Lint subscription strings in CI the same way you lint config files","Remember the extracted name is the registry key — reuse it verbatim in TTL entries and client requests"],"tags":["linera","graphql","cli","parsing","subscription"],"backgroundTag":"graphql-syntax-error","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}