hasura/graphql-engine · error · FieldError

subscription are not supported over HTTP

Error message

subscription are not supported over HTTP

What it means

FieldError::SubscriptionsNotSupported — a GraphQL subscription operation was sent over the plain HTTP transport, which this engine only handles for queries and mutations. The error is deterministic: the HTTP execution path explicitly rejects subscription operations.

Source

Thrown at v3/crates/execute/src/error.rs:41

/// Field errors are raised during execution from a root field
/// Ref: <https://spec.graphql.org/October2021/#sec-Errors.Field-errors>
#[allow(clippy::duplicated_attributes)] // suppress spurious warnings from Clippy
#[derive(Error, Debug, Transitive)]
#[transitive(from(json::Error, FieldInternalError))]
#[transitive(from(NDCUnexpectedError, FieldInternalError))]
#[transitive(from(gql::normalized_ast::Error, FieldInternalError))]
#[transitive(from(gql::introspection::Error, FieldInternalError))]
#[transitive(from(FilterPredicateError, FieldInternalError))]
pub enum FieldError {
    #[error("error from data source: {}", connector_error.error_response.message())]
    NDCExpected {
        connector_error: ndc_client::ConnectorError,
    },

    #[error("field '{field_name:} not found in _Service")]
    FieldNotFoundInService { field_name: String },

    #[error("subscription are not supported over HTTP")]
    SubscriptionsNotSupported,

    #[error(
        "Relationship '{name}' is either remote or not having 'relation_comparisons' NDC capability; not supported for filtering"
    )]
    RelationshipPredicatesNotSupported { name: RelationshipName },

    #[error("internal error: {0}")]
    InternalError(#[from] FieldInternalError),
}

impl FieldError {
    fn get_details(&self) -> Option<serde_json::Value> {
        match self {
            Self::NDCExpected { connector_error } => {
                Some(connector_error.error_response.details().clone())
            }
            Self::InternalError(internal) => internal.get_details(),

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Use the WebSocket (graphql-ws/subscription-transport-ws) endpoint for subscriptions
  2. Change the operation to a query/mutation if realtime behavior isn't needed
  3. Configure your GraphQL client (urql/apollo-relay etc.) to route subscriptions to the WS URL

Example fix

# before
POST /graphql  { "query": "subscription { userAdded { id } }" }

# after
# connect via websocket
new GraphQLWsLink(new WebSocketClient('wss://host/graphql'))
Defensive patterns

Strategy: validation

Validate before calling

import { parse } from 'graphql';
const opType = parse(query).definitions[0].operation;
if (opType === 'subscription') throw new Error('use the WebSocket endpoint for subscriptions');

Type guard

fn is_subscription(doc: &graphql::Request) -> bool { /* inspect parsed operation type */ true }

Try / catch

Match FieldError::SubscriptionsNotSupported and return an HTTP 400 with a message directing the client to the WebSocket endpoint.

Prevention

When it happens

Trigger: Sending a subscription document (operation type 'subscription') to the engine's HTTP endpoint, e.g. POST /graphql with a subscription query, instead of opening a WebSocket connection.

Common situations: Clients or tools defaulting to HTTP for all operation types, missing WebSocket configuration in the GraphQL client, or test scripts POSTing subscription queries.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/5e977042b21d25a3. Report an issue: GitHub.