{"record":{"id":"296d7fc377b67a27","repo":"hasura/graphql-engine","slug":"explain-error-0","errorCode":null,"errorMessage":"explain error: {0}","messagePattern":"explain error: (.+?)","errorType":"exception","errorClass":"RequestError::ExplainError","httpStatus":null,"severity":"error","filePath":"v3/crates/graphql/frontend/src/error.rs","lineNumber":23,"sourceCode":"use tracing_util::{ErrorVisibility, TraceableError};\n\n/// Request errors are raised before execution of root fields begins.\n/// Ref: <https://spec.graphql.org/October2021/#sec-Errors.Request-errors>\n#[derive(Debug, thiserror::Error)]\npub enum RequestError {\n    #[error(\"parsing failed: {0}\")]\n    ParseFailure(#[from] gql::ast::spanning::Positioned<gql::parser::Error>),\n\n    #[error(\"validation failed: {0}\")]\n    ValidationFailed(#[from] gql::validation::Error),\n\n    #[error(\"{0}\")]\n    IRConversionError(#[from] graphql_ir::Error),\n\n    #[error(\"{0}\")]\n    GraphQlPlanError(#[from] graphql_ir::GraphqlIrPlanError),\n\n    #[error(\"explain error: {0}\")]\n    ExplainError(String),\n}\n\nimpl RequestError {\n    pub fn to_graphql_error(&self, expose_internal_errors: ExposeInternalErrors) -> GraphQLError {\n        let message = match (self, expose_internal_errors) {\n            // Error messages for internal errors from IR conversion and Plan generations are masked.\n            (\n                Self::IRConversionError(graphql_ir::Error::Internal(_)),\n                ExposeInternalErrors::Censor,\n            ) => \"internal error\".into(),\n            (e, _) => e.to_string(),\n        };\n        // We are using the visibility of the error to determine if it is an internal error or not. We are assuming that\n        // if we are showing the error message to the user, it is something that they can fix on their end.\n        let is_internal = self.visibility() == ErrorVisibility::Internal;\n        GraphQLError {\n            message,","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/graphql/frontend/src/error.rs#L5-L41","documentation":"RequestError::ExplainError is a catch-all for failures encountered while producing a query explanation (plan/preview) for a GraphQL request. It carries a String message describing what went wrong during the explain pipeline, prefixed with 'explain error: '. It is distinct from parse/validation errors: the request was understood, but explaining it failed.","triggerScenarios":"Invoking the explain/plan-preview endpoint or generating an execution plan explanation for a query whose plan cannot be rendered — for example unsupported constructs in explain mode, IR-to-plan conversion problems during explanation, or downstream errors while formatting the plan for display.","commonSituations":"Running explain on queries using newer features not yet supported by the explain pipeline; explain endpoints hit during engine upgrades where plan formatting changed; internal errors in the planner surfacing only in explain mode.","solutions":["Read the embedded String message; it usually names the unsupported construct or failing stage","Try explaining a simplified version of the query to isolate which field/feature breaks explanation","Execute the query normally — if it runs, the issue is explain-specific and can be reported upstream","Update the engine to a version where explain supports the construct in question"],"exampleFix":"// before\nPOST /v1/graphql/explain  { \"query\": \"query { ... complex nested with @include }\" }\n\n// after\nPOST /v1/graphql/explain  { \"query\": \"query { ... simplified top-level field }\" }","handlingStrategy":"fallback","validationCode":"// Guard explain-only features: reject explain requests for constructs\n// your version can't explain before calling the endpoint:\nif query.contains_directives(&[\"@include\", \"@skip\"]) && mode == Explain {\n    return Err(ExplainUnsupported.into());\n}","typeGuard":null,"tryCatchPattern":"let plan = match frontend.explain(&req).await {\n    Ok(p) => p,\n    Err(RequestError::ExplainError(msg)) => {\n        tracing::warn!(%msg, \"explain failed; falling back to execution-only path\");\n        return execution_only(&req).await;\n    }\n    Err(e) => return Err(e.into()),\n};","preventionTips":["Treat explain as best-effort: wrap it with a fallback to normal execution","Pin the engine version and read release notes for explain-pipeline changes","Report explain failures with the embedded message upstream — they often indicate planner gaps"],"tags":["rust","graphql","explain","plan-preview","query-planning"],"backgroundTag":"graphql-explain-failed","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}