{"record":{"id":"657c56aeb60e1c84","repo":"actix/actix-web","slug":"all-default-headers-must-be-added-before-cloning","errorCode":null,"errorMessage":"All default headers must be added before cloning.","messagePattern":"All default headers must be added before cloning\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"actix-web/src/middleware/default_headers.rs","lineNumber":67,"sourceCode":"impl DefaultHeaders {\n    /// Constructs an empty `DefaultHeaders` middleware.\n    #[inline]\n    pub fn new() -> DefaultHeaders {\n        DefaultHeaders::default()\n    }\n\n    /// Adds a header to the default set.\n    ///\n    /// # Panics\n    /// Panics when resolved header name or value is invalid.\n    #[allow(clippy::should_implement_trait)]\n    pub fn add(mut self, header: impl TryIntoHeaderPair) -> Self {\n        // standard header terminology `insert` or `append` for this method would make the behavior\n        // of this middleware less obvious since it only adds the headers if they are not present\n\n        match header.try_into_pair() {\n            Ok((key, value)) => Rc::get_mut(&mut self.inner)\n                .expect(\"All default headers must be added before cloning.\")\n                .headers\n                .append(key, value),\n            Err(err) => panic!(\"Invalid header: {}\", err.into()),\n        }\n\n        self\n    }\n\n    #[doc(hidden)]\n    #[deprecated(\n        since = \"4.0.0\",\n        note = \"Prefer `.add((key, value))`. Will be removed in v5.\"\n    )]\n    pub fn header<K, V>(self, key: K, value: V) -> Self\n    where\n        HeaderName: TryFrom<K>,\n        <HeaderName as TryFrom<K>>::Error: Into<HttpError>,\n        HeaderValue: TryFrom<V>,","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/actix/actix-web/blob/4d435abc281842f3cbee165b6cde739e001d3a25/actix-web/src/middleware/default_headers.rs#L49-L85","documentation":"This is a runtime panic from `DefaultHeaders::add()`. The middleware stores headers in `Rc<Inner>`; `add()` calls `Rc::get_mut(&mut self.inner)` at line 66 to obtain mutable access. If the `Rc` has been cloned (e.g., the middleware was `.clone()`d or already registered with `.wrap()`), `get_mut` returns `None` and the `.expect()` at line 67 panics.","triggerScenarios":"Calling `.add(...)` on a `DefaultHeaders` instance after it has been cloned, or after it has been passed to `.wrap()`. The `.wrap()` call may clone the middleware internally before `add()` is called. For example: `let mw = DefaultHeaders::new(); App::new().wrap(mw.clone()); mw.add((\"X\", \"1\"));`","commonSituations":"Chaining `.add()` calls after the middleware has been wrapped into an app or scope, sharing a `DefaultHeaders` instance across multiple `App` or `Scope` registrations, or calling `.clone()` explicitly.","solutions":["Add all headers before calling `.wrap()`: build the complete `DefaultHeaders` first, then register it","Do not clone `DefaultHeaders` before adding headers; use a fresh `DefaultHeaders::new()` for each registration","Chain all `.add()` calls in a single builder expression: `DefaultHeaders::new().add((\"X\", \"1\")).add((\"Y\", \"2\"))`"],"exampleFix":"// before\nlet headers = DefaultHeaders::new().add((\"X-Version\", \"1.0\"));\nlet app = App::new().wrap(headers.clone());\nheaders.add((\"X-Extra\", \"foo\")); // panics: already cloned\n\n// after\nlet headers = DefaultHeaders::new()\n    .add((\"X-Version\", \"1.0\"))\n    .add((\"X-Extra\", \"foo\"));\nlet app = App::new().wrap(headers);","handlingStrategy":"validation","validationCode":"// Build the complete DefaultHeaders before wrapping it.\n// Never call .add() after .wrap() or .clone().\nlet default_headers = middleware::DefaultHeaders::new()\n    .add((\"X-Version\", \"1.0\"))\n    .add((\"X-Request-Id\", \"auto\"));\n// Only now register:\nlet app = App::new().wrap(default_headers);","typeGuard":null,"tryCatchPattern":"// Rust does not catch panics in normal code.\n// The guard is structural: add all headers before wrapping.\n// If sharing across apps, construct a fresh DefaultHeaders each time:\nfn make_headers() -> DefaultHeaders {\n    DefaultHeaders::new()\n        .add((\"X-Version\", \"1.0\"))\n}\nlet app1 = App::new().wrap(make_headers());\nlet app2 = App::new().wrap(make_headers());","preventionTips":["Chain all .add() calls before passing the middleware to .wrap()","Never call .add() after .wrap() or .clone()","Construct a fresh DefaultHeaders::new() for each App or Scope registration","Use a factory function that returns a fully-built DefaultHeaders to avoid accidental sharing"],"tags":["rust","actix-web","middleware","runtime-panic","builder-pattern","headers"],"backgroundTag":null,"analyzedSha":"4d435abc281842f3cbee165b6cde739e001d3a25","analyzedAt":"2026-08-09T01:01:40.926Z","contentChangedAt":"2026-08-09T01:01:40.926Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}