hasura/graphql-engine · error · Error

Error serializing the modified response: {0}

Error message

Error serializing the modified response: {0}

What it means

After the hook mutates the response, the pre-response plugin failed to serialize the modified response back to JSON (serde_json::Error). This happens on the write side, when producing the body to return.

Source

Thrown at v3/crates/plugins/pre-response-plugin/src/execute/common.rs:29

use reqwest::header::HeaderValue;
use serde::Serialize;
use tracing_util::{ErrorVisibility, TraceableError};

#[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("Error parsing the request: {0}")]
    PluginRequestParseError(serde_json::Error),
    #[error("Error parsing the engine response: {0}")]
    EngineResponseParseError(serde_json::Error),
    #[error("Unexpected status code: {0}")]
    UnexpectedStatusCode(u16),
    #[error("Error serializing the modified response: {0}")]
    ResponseSerializationError(serde_json::Error),
    #[error("Error while preparing the response: {0}")]
    ResponsePreparationError(axum::http::Error),
}

impl TraceableError for Error {
    fn visibility(&self) -> ErrorVisibility {
        ErrorVisibility::Internal
    }
}

impl Error {
    pub fn to_graphql_response(self) -> lang_graphql::http::Response {
        let is_internal = match &self {
            Error::ErrorWhileMakingHTTPRequestToTheHook(_, _)
            | Error::UnexpectedStatusCode(_)
            | Error::ResponseSerializationError(_)
            | Error::ResponsePreparationError(_) => false,

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Inspect the modified response produced by the hook for non-serializable values (NaN, Infinity, invalid map keys).
  2. Fix the hook to emit plain, JSON-safe values.
  3. Sanitize/normalize hook output before merging into the response.

Example fix

// before (hook emits NaN)
let v = serde_json::json!({ "score": f64::NAN });

// after
let v = serde_json::json!({ "score": null });
Defensive patterns

Strategy: validation

Validate before calling

// hook side: ensure JSON-safe values before returning
fn sanitize(v: f64) -> serde_json::Value {
    if v.is_finite() { v.into() } else { serde_json::Value::Null }
}

Try / catch

match serde_json::to_value(&modified) {
    Ok(v) => v,
    Err(e) => { tracing::warn!("hook produced unserializable response: {e}"); engine_response_untouched }
}

Prevention

When it happens

Trigger: The hook returns response content that cannot round-trip through the engine's response model — e.g. non-serializable values, or a structure that serde rejects on serialize (map with non-string keys, NaN in serde_json strict mode).

Common situations: Hook injecting unusual JSON values (NaN/Infinity floats) that serde_json refuses; deeply mutated structures violating the response type.

Related errors


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