E0275 in 7 s at the default recursion limit becomes a multi-hour hang at `recursion_limit = "4096"`, which is what the E0275 help text suggests
@hammadk306 is already working on this.
Since Sep 6, 2026.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Summary
A #[derive(Serialize)] on an internally tagged enum whose newtype variants hold Self fails with E0275 in about 7 seconds at the default recursion limit. The diagnostic's help: says to raise recursion_limit. Raising it to 4096 turns the same failure into a trait-solver search that did not finish in 54 minutes locally and hit a 240-minute CI cap twice, at 100 % of one core and flat 375 MB RSS, with no output. The overflow is real either way (the impl genuinely does not exist), so the limit is not the problem; the solver keeps exploring a strictly-deeper candidate at every level until the limit is reached, and 4096 levels is effectively unbounded.
Related: #127315, #113359 (hang instead of overflow), but this one has a twist: the default limit does report E0275, and the diagnostic itself points the user at the setting that produces the hang.
Reproducer
Cargo.toml
[package]
name = "repro"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "=1.0.228", features = ["derive"] }
serde_json = "=1.0.150"
src/main.rs
// Uncomment the next line to turn the 7 s E0275 into a hang.
// #![recursion_limit = "4096"]
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Expr {
Eq { field: String },
And(Vec<Expr>),
Not(Box<Expr>),
}
fn main() {
let _ = serde_json::to_string(&Expr::Eq { field: "a".into() }).unwrap();
}
Actual behaviour
Default limit (cargo build, rustc 1.98.1, 7 s for the crate after deps):
error[E0275]: overflow evaluating the requirement `&mut Vec<u8>: std::io::Write`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`repro`)
= note: required for `&mut serde_json::Serializer<&mut Vec<u8>>` to implement `_::_serde::Serializer`
With #![recursion_limit = "4096"]: rustc runs at 99.5 % of one core, RSS flat at ~375 MB, no diagnostics, until killed. On this minimal crate: still compiling when killed at a 300 s cap (rustc 1.98.1), against 7 s to E0275 without the attribute. On the originating 16-variant enum (same three self-referential variants plus 13 struct variants holding serde_json::Value): > 54 min locally on rustc 1.94.1 and 1.98.1 (CARGO_INCREMENTAL=0 and --release make no difference), and 240 min 16 s twice on GitHub's ubuntu-latest before the job cap killed it. cargo check passes (the overflow only surfaces when to_string is monomorphised).
Expected behaviour
Either the same E0275 after a bounded amount of work, or the depth counter to notice that each level nests a strictly larger serializer type (TaggedSerializer<TaggedSerializer<…>>) and cut off. At minimum, the help: text should not recommend the setting that turns a 7-second error into a hang when the obligation is provably unsatisfiable.
Why the recursion happens (for context)
Under #[serde(tag = "type")] a newtype variant serialises through serde::__private::ser::TaggedSerializer<S>, so proving Expr: Serialize for serializer S requires proving it for TaggedSerializer<S>, which requires it for TaggedSerializer<TaggedSerializer<S>>, and so on. Changing the three variants to struct variants (And { filters: Vec<Self> }) compiles in 5 s under the default limit and round-trips, which is how the originating project fixed it (ruvnet/ruvector, crates/ruvector-filter/src/expression.rs).
Meta
rustc 1.98.1 (48a229cea 2026-09-01)
host: x86_64-unknown-linux-gnu
Also reproduced on rustc 1.94.1 (e408947bf 2026-03-25). serde 1.0.228 and 1.0.229, serde_json 1.0.150 and 1.0.151.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.