{"record":{"id":"bbe958426f9b96b5","repo":"hasura/graphql-engine","slug":"invalid-header-name-0-bbe958","errorCode":null,"errorMessage":"Invalid header name {0}","messagePattern":"Invalid header name (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/crates/plugins/pre-route-plugin/src/execute.rs","lineNumber":34,"sourceCode":"use tracing_util::{\n    ErrorVisibility, SpanVisibility, Traceable, TraceableError, set_attribute_on_active_span,\n};\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    #[error(\"HTTP method {0} not supported\")]\n    UnsupportedHTTPMethod(String),\n    #[error(\"Invalid header name {0}\")]\n    InvalidHeaderName(String),\n    #[error(\"Invalid header value {0}\")]\n    InvalidHeaderValue(String),\n    #[error(\"Not found\")]\n    NotFound,\n    // Only used in the pre-route plugin handler function. Defined to ensure consistent\n    // response formatting in IntoResponse impl.\n    #[error(\"Cannot load pre-route plugins: {0}\")]\n    CannotLoadPlugins(String),\n}\n\nimpl TraceableError for Error {\n    fn visibility(&self) -> ErrorVisibility {\n        ErrorVisibility::Internal\n    }\n}\n\nimpl IntoResponse for Error {","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/plugins/pre-route-plugin/src/execute.rs#L16-L52","documentation":"The pre-route hook supplied a header name that is not a valid HTTP header name (invalid characters, empty, or malformed), and the executor rejected it while applying hook instructions to the request. The offending name is included as {0}.","triggerScenarios":"The hook's response instructs the engine to add/override a header with a name containing spaces, non-ASCII characters, or CR/LF — anything http::HeaderName::from_str would reject.","commonSituations":"Hook passing through unvalidated user input as header names; header name typos; header-injection attempts or accidental newlines in config-driven header maps.","solutions":["Validate header names in the hook with http::HeaderName::from_str before returning them.","Whitelist allowed header names the hook may set.","Trim input and reject names containing spaces, colons, or control characters.","Log the offending name from the error message to locate the source."],"exampleFix":"// before (hook)\ninstructions.push(HeaderOp { name: user_input, value });\n\n// after (hook)\nlet name = http::HeaderName::from_str(user_input.trim())\n    .map_err(|_| Error::InvalidHeaderName(user_input.into()))?;\ninstructions.push(HeaderOp { name: name.to_string(), value });","handlingStrategy":"validation","validationCode":"fn valid_header_name(name: &str) -> bool {\n    !name.is_empty() && http::HeaderName::from_str(name).is_ok()\n}","typeGuard":"fn is_valid_header_name(n: &str) -> bool {\n    http::HeaderName::from_str(n.trim()).is_ok()\n}","tryCatchPattern":"if let Error::InvalidHeaderName(name) = &e { tracing::warn!(\"dropping invalid header from hook: {name}\"); }","preventionTips":["Validate header names with http::HeaderName::from_str in the hook before returning.","Allowlist headers a hook may set.","Sanitize user-sourced strings of CR/LF and spaces."],"tags":["http","headers","validation","plugin","rust","pre-route-hook"],"backgroundTag":"invalid-http-header","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}