hasura/graphql-engine · error · Error

Unexpected status code: {0}

Error message

Unexpected status code: {0}

What it means

The pre-parse plugin executor received an HTTP response from the hook with a status code it does not recognize as success or as the special continue-signal (299). Any status outside the accepted set is surfaced with its numeric code.

Source

Thrown at v3/crates/plugins/pre-parse-plugin/src/execute.rs:31

use tracing_util::{
    ErrorVisibility, SpanVisibility, Traceable, TraceableError, set_attribute_on_active_span,
};

/// HTTP status code used by pre-parse plugins to indicate they want to continue
/// processing with a modified request body.
///
/// We use 299 (an unassigned 2xx status code) as a special signal for this.
const CONTINUE_WITH_REQUEST_STATUS: u16 = 299;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("Error while making the HTTP request to the pre-parse plugin {0} - {1}")]
    ErrorWhileMakingHTTPRequestToTheHook(String, reqwest::Error),
    #[error("Error while building the request for the pre-parse plugin {0} - {1}")]
    BuildRequestError(String, String),
    #[error("Reqwest error: {0}")]
    ReqwestError(reqwest::Error),
    #[error("Unexpected status code: {0}")]
    UnexpectedStatusCode(u16),
    #[error("Error parsing the request: {0}")]
    PluginRequestParseError(serde_json::error::Error),
}

impl Error {
    pub fn is_internal(&self) -> bool {
        match self {
            Error::ErrorWhileMakingHTTPRequestToTheHook(_, _) | Error::UnexpectedStatusCode(_) => {
                false
            }
            Error::BuildRequestError(_, _)
            | Error::ReqwestError(_)
            | Error::PluginRequestParseError(_) => true,
        }
    }

    pub fn into_graphql_error(self) -> lang_graphql::http::GraphQLError {

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Check the plugin service logs to see why it returned that status.
  2. Fix contract mismatches: confirm the hook's expected payload/response shape matches the engine's plugin version.
  3. Align auth credentials/tokens between engine and plugin if the status is 401/403.
  4. Upgrade engine and plugin crates together so the status-code contract (including 299 continue) matches.
Defensive patterns

Strategy: try-catch

Try / catch

if let Error::UnexpectedStatusCode(code) = &e {
    tracing::error!("hook returned {code}");
    // decide: fail open (continue without plugin) vs fail closed
}

Prevention

When it happens

Trigger: The hook returns 4xx/5xx or any unexpected status; e.g. the plugin returns 400 for a malformed hook payload, or 500 because the plugin itself errored while processing the request.

Common situations: Plugin version mismatch changing the expected contract; plugin returning an auth error (401/403) because shared secrets differ; plugin bug returning 500.

Related errors


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