{"record":{"id":"3cd12074eef8177a","repo":"hasura/graphql-engine","slug":"unexpected-status-code-0-3cd120","errorCode":null,"errorMessage":"Unexpected status code: {0}","messagePattern":"Unexpected status code: (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/crates/plugins/pre-parse-plugin/src/execute.rs","lineNumber":31,"sourceCode":"use tracing_util::{\n    ErrorVisibility, SpanVisibility, Traceable, TraceableError, set_attribute_on_active_span,\n};\n\n/// HTTP status code used by pre-parse plugins to indicate they want to continue\n/// processing with a modified request body.\n///\n/// We use 299 (an unassigned 2xx status code) as a special signal for this.\nconst CONTINUE_WITH_REQUEST_STATUS: u16 = 299;\n\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    #[error(\"Error while making the HTTP request to the pre-parse plugin {0} - {1}\")]\n    ErrorWhileMakingHTTPRequestToTheHook(String, reqwest::Error),\n    #[error(\"Error while building the request for the pre-parse plugin {0} - {1}\")]\n    BuildRequestError(String, String),\n    #[error(\"Reqwest error: {0}\")]\n    ReqwestError(reqwest::Error),\n    #[error(\"Unexpected status code: {0}\")]\n    UnexpectedStatusCode(u16),\n    #[error(\"Error parsing the request: {0}\")]\n    PluginRequestParseError(serde_json::error::Error),\n}\n\nimpl Error {\n    pub fn is_internal(&self) -> bool {\n        match self {\n            Error::ErrorWhileMakingHTTPRequestToTheHook(_, _) | Error::UnexpectedStatusCode(_) => {\n                false\n            }\n            Error::BuildRequestError(_, _)\n            | Error::ReqwestError(_)\n            | Error::PluginRequestParseError(_) => true,\n        }\n    }\n\n    pub fn into_graphql_error(self) -> lang_graphql::http::GraphQLError {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/plugins/pre-parse-plugin/src/execute.rs#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"Plugin version mismatch changing the expected contract; plugin returning an auth error (401/403) because shared secrets differ; plugin bug returning 500.","solutions":["Check the plugin service logs to see why it returned that status.","Fix contract mismatches: confirm the hook's expected payload/response shape matches the engine's plugin version.","Align auth credentials/tokens between engine and plugin if the status is 401/403.","Upgrade engine and plugin crates together so the status-code contract (including 299 continue) matches."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Error::UnexpectedStatusCode(code) = &e {\n    tracing::error!(\"hook returned {code}\");\n    // decide: fail open (continue without plugin) vs fail closed\n}","preventionTips":["Contract-test the hook's status codes (including the 299 continue signal) in CI.","Return only documented statuses from hook implementations.","Version-pin engine and plugin together."],"tags":["http","status-code","plugin","rust","pre-parse-hook"],"backgroundTag":"unexpected-http-status","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}