hasura/graphql-engine · error · Error

Error parsing the request: {0}

Error message

Error parsing the request: {0}

What it means

Thrown when the JSON payload returned by (or sent to) the pre-parse hook fails to deserialize into the expected plugin request structure (serde_json::error::Error). This is a schema mismatch between what the engine serializes/expects and what the hook produces/expects.

Source

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

};

/// 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 {
        lang_graphql::http::GraphQLError {
            message: self.to_string(),

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Pin engine and plugin crates to compatible versions (schema contract).
  2. Log the raw hook response body to see exactly what failed to parse.
  3. If a proxy intercepts the hook, exclude the plugin route or fix the proxy's error responses.
  4. Add tolerant serde attributes (Option fields, #[serde(default)]) on the plugin schema if you control it.

Example fix

// before (strict, breaks when hook omits a field)
#[derive(Deserialize)]
struct HookRequest { op: String, target: String }

// after
#[derive(Deserialize)]
struct HookRequest { op: String, #[serde(default)] target: Option<String> }
Defensive patterns

Strategy: validation

Validate before calling

// hook side: verify payload matches before responding
let parsed: PluginRequest = serde_json::from_str(&body)
    .map_err(|e| (http::StatusCode::BAD_REQUEST, e.to_string()));

Try / catch

match serde_json::from_str::<PluginRequest>(&raw) {
    Ok(r) => r,
    Err(e) => { tracing::warn!("schema mismatch: {e}"); fallback_default() }
}

Prevention

When it happens

Trigger: The hook returns a JSON body whose fields don't match the expected request type (missing fields, wrong types, trailing data), or the engine fails to parse the hook's instruction payload.

Common situations: Engine and plugin built from different versions with a changed schema; plugin returning an error JSON instead of the expected payload; a proxy injecting an HTML error page that gets parsed as JSON.

Related errors


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