actix/actix-web · error
All default headers must be added before cloning.
Error message
All default headers must be added before cloning.
What it means
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.
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"))`
Example fix
// before
let headers = DefaultHeaders::new().add(("X-Version", "1.0"));
let app = App::new().wrap(headers.clone());
headers.add(("X-Extra", "foo")); // panics: already cloned
// after
let headers = DefaultHeaders::new()
.add(("X-Version", "1.0"))
.add(("X-Extra", "foo"));
let app = App::new().wrap(headers); Defensive patterns
Strategy: validation
Validate before calling
// Build the complete DefaultHeaders before wrapping it.
// Never call .add() after .wrap() or .clone().
let default_headers = middleware::DefaultHeaders::new()
.add(("X-Version", "1.0"))
.add(("X-Request-Id", "auto"));
// Only now register:
let app = App::new().wrap(default_headers); Try / catch
// Rust does not catch panics in normal code.
// The guard is structural: add all headers before wrapping.
// If sharing across apps, construct a fresh DefaultHeaders each time:
fn make_headers() -> DefaultHeaders {
DefaultHeaders::new()
.add(("X-Version", "1.0"))
}
let app1 = App::new().wrap(make_headers());
let app2 = App::new().wrap(make_headers()); Prevention
- 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
When it happens
Trigger: 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"));`
Common situations: 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.
Related errors
- Invalid header name
- Invalid header value
- cannot reuse response builder
- Value for parameter is not available
- actix-http client only supports versions http/1.1 & http/2
AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09).
Data as JSON: /api/errors/657c56aeb60e1c84.
Report an issue: GitHub.
Appendix: source
Thrown at actix-web/src/middleware/default_headers.rs:67
impl DefaultHeaders {
/// Constructs an empty `DefaultHeaders` middleware.
#[inline]
pub fn new() -> DefaultHeaders {
DefaultHeaders::default()
}
/// Adds a header to the default set.
///
/// # Panics
/// Panics when resolved header name or value is invalid.
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, header: impl TryIntoHeaderPair) -> Self {
// standard header terminology `insert` or `append` for this method would make the behavior
// of this middleware less obvious since it only adds the headers if they are not present
match header.try_into_pair() {
Ok((key, value)) => Rc::get_mut(&mut self.inner)
.expect("All default headers must be added before cloning.")
.headers
.append(key, value),
Err(err) => panic!("Invalid header: {}", err.into()),
}
self
}
#[doc(hidden)]
#[deprecated(
since = "4.0.0",
note = "Prefer `.add((key, value))`. Will be removed in v5."
)]
pub fn header<K, V>(self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
HeaderValue: TryFrom<V>,View on GitHub (pinned to 4d435abc28)