Rust Error E0532: Expected Unit Struct, Unit Variant or Constant, Found Tuple Variant
E0532 means: the shape of your pattern doesn’t match the shape of the thing you named. The classic case is a match arm like Shape::Circle => for a variant that holds data, Circle(f64). Rust wants the parentheses: Shape::Circle(_). The reverse mistake gets the same code, with the other wording “expected tuple struct or tuple variant”: parentheses on something that has no data in parentheses, like Status::Active(). Both are one-line fixes. (This page is part of Rust compiler errors explained.)
The error message
Section titled “The error message”error[E0532]: expected unit struct, unit variant or constant, found tuple variant `Shape::Circle` --> src/main.rs:8:9 |2 | Circle(f64), | ----------- `Shape::Circle` defined here...8 | Shape::Circle => "circle", // ❌ `Circle` holds a value | ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Shape::Circle(_)`This is the program that produces it:
enum Shape { Circle(f64), Square(f64),}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "circle", // ❌ `Circle` holds a value Shape::Square(_) => "square", }}
fn main() { println!("{}", name(&Shape::Circle(1.0)));}What it means
Section titled “What it means”The ^^^ points at Shape::Circle on line 8, and the --- on line 2 shows how it was defined: Circle(f64), a tuple variant that carries one f64. A pattern that is only a name, with nothing after it, must be one of three things:
- a unit struct, like
struct Empty; - a unit variant, a variant with no data, like
Shape::EmptyorNone - a constant, like
const LIMIT: u32 = 100;
Shape::Circle is none of these. The help line gives the fix right away: Shape::Circle(_), “a circle, whatever its value”.
The other E0532 headline is the mirror image: expected tuple struct or tuple variant, found unit variant `Status::Active` (or found struct, or found constant). There, you wrote parentheses after a name, and the thing you named doesn’t take values in parentheses.
It’s like a form that asks “Pet: dog (name: ____)”. Writing just “dog” leaves the name box empty, and writing “fish (name: Bubbles)” where the form says “fish” with no box adds a box that isn’t there.
Why Rust does this
Section titled “Why Rust does this”Every struct and enum variant has one of three shapes, and you write it the same way when you create it and when you match on it (see Enums can hold data):
| Kind | Create it | Match it |
|---|---|---|
Unit: Empty |
Shape::Empty |
Shape::Empty |
Tuple: Circle(f64) |
Shape::Circle(1.0) |
Shape::Circle(r) or Shape::Circle(..) |
Struct: Rect { w: f64, h: f64 } |
Shape::Rect { w: 2.0, h: 3.0 } |
Shape::Rect { w, h } or Shape::Rect { .. } |
Because the shapes are strict, a pattern always looks like the value it matches, and you can read a match and see what data each arm has. It also helps when you change a type: if Empty later gains a value and becomes Empty(u32), every old Shape::Empty arm is flagged, instead of quietly matching something new.
How to fix it
Section titled “How to fix it”Fix 1: Add (_), (..) or names for the values
Section titled “Fix 1: Add (_), (..) or names for the values”Choose this when the message says found tuple variant or found tuple struct, which is the most common E0532. Use _ for each value you don’t need, .. to skip all of them at once, or a name when you want to use the value:
enum Shape { Circle(f64), Rect(f64, f64), Empty,}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle(_) => "circle", // ✅ one field, ignored Shape::Rect(..) => "rectangle", // ✅ any number of fields, all ignored Shape::Empty => "nothing", // a unit variant: no parentheses }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ bind the field because we need it Shape::Rect(w, h) => w * h, Shape::Empty => 0.0, }}
fn main() { let shapes = [Shape::Circle(1.0), Shape::Rect(2.0, 3.0), Shape::Empty]; for shape in &shapes { println!("{}: {:.2}", name(shape), area(shape)); } let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle(_))).count(); println!("{} circle(s)", circles);}Output:
circle: 3.14rectangle: 6.00nothing: 0.001 circle(s)(..) is handy for variants with several values, and it keeps working if you add one more later. See Ignoring parts with _ and ...
Fix 2: Remove the () from a unit variant
Section titled “Fix 2: Remove the () from a unit variant”Choose this when the message says found unit variant or found unit struct. The variant holds no data, so there’s nothing to put in parentheses:
error[E0532]: expected tuple struct or tuple variant, found unit variant `Status::Active` --> src/main.rs:8:9 |2 | Active, | ------ `Status::Active` defined here...8 | Status::Active() => "active", // ❌ `Active` holds no data | ^^^^^^^^^^^^^^^^ help: use this syntax instead: `Status::Active`The program behind it:
enum Status { Active, Banned(String),}
fn label(s: &Status) -> &'static str { match s { Status::Active() => "active", // ❌ `Active` holds no data Status::Banned(_) => "banned", }}
fn main() { println!("{}", label(&Status::Active));}Write the name alone, both in the pattern and where you create the value:
#[derive(Debug)]enum Status { Active, Banned(String),}
fn label(s: &Status) -> String { match s { Status::Active => String::from("active"), // ✅ unit variant: no () Status::Banned(reason) => format!("banned ({})", reason), }}
fn main() { println!("{}", label(&Status::Active)); println!("{}", label(&Status::Banned(String::from("spam")))); let s = Status::Active; // ✅ and no () when you create it either println!("{:?}", s);}Output:
activebanned (spam)ActiveIf you meant the variant to carry data, change the definition instead, for example Active(u64) for a “since” timestamp, and then Status::Active(_) is the right pattern.
Fix 3: Use braces for a struct with named fields
Section titled “Fix 3: Use braces for a struct with named fields”Choose this when the message says found struct. A struct with named fields, struct Point { x: i32, y: i32 }, is destructured with braces and field names, not with parentheses:
error[E0532]: expected tuple struct or tuple variant, found struct `Point` --> src/main.rs:8:9 |1 | / struct Point {2 | | x: i32,3 | | y: i32,4 | | } | |_- `Point` defined here...8 | let Point(x, y) = p; // ❌ `Point` has named fields | ^^^^^^^^^^^ help: use struct pattern syntax instead: `Point { x, y }`The program behind it:
struct Point { x: i32, y: i32,}
fn main() { let p = Point { x: 3, y: 4 }; let Point(x, y) = p; // ❌ `Point` has named fields println!("{} {}", x, y);}rustc’s suggestion Point { x, y } is exactly right. Use field: name when you want a different variable name:
struct Point { x: i32, y: i32,}
struct Meters(f64); // a tuple struct: here parentheses are right
fn main() { let p = Point { x: 3, y: 4 }; let Point { x, y } = p; // ✅ braces and the field names println!("x = {}, y = {}", x, y);
let q = Point { x: -1, y: 7 }; let Point { x: left, y: up } = q; // ✅ rename while destructuring println!("left = {}, up = {}", left, up);
let Meters(m) = Meters(2.5); // ✅ tuple struct, tuple pattern println!("{} m", m);}Output:
x = 3, y = 4left = -1, up = 72.5 mFor an enum variant with named fields, Shape::Rect(w, h) for Rect { w: f64, h: f64 }, the same mistake gives a different code, E0164. The fix is the same: braces.
Fix 4: Use a constant or a match guard instead of a function call
Section titled “Fix 4: Use a constant or a match guard instead of a function call”Choose this when the message says expected a pattern, found a function call. A pattern must be known at compile time, and a function call isn’t:
error[E0532]: expected a pattern, found a function call --> src/main.rs:7:14 |7 | Some(limit()) => "full", // ❌ a function call can't be a pattern | ^^^^^ not a tuple struct or tuple variant | = note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>The program behind it:
fn limit() -> u32 { 100}
fn status(users: Option<u32>) -> &'static str { match users { Some(limit()) => "full", // ❌ a function call can't be a pattern Some(_) => "open", None => "closed", }}
fn main() { println!("{}", status(Some(100)));}If the value never changes, make it a const; constants can be used inside patterns. If it has to be computed, bind the value to a name and compare in a match guard:
const LIMIT: u32 = 100; // a constant can be used inside a pattern
fn limit_for(premium: bool) -> u32 { if premium { 500 } else { 100 }}
fn status(users: Option<u32>) -> &'static str { match users { Some(LIMIT) => "full", // ✅ a constant Some(_) => "open", None => "closed", }}
fn status_for(users: Option<u32>, premium: bool) -> &'static str { match users { Some(n) if n >= limit_for(premium) => "full", // ✅ call the function in a guard Some(_) => "open", None => "closed", }}
fn main() { println!("{}", status(Some(100))); println!("{}", status(Some(42))); println!("{}", status(None)); println!("{}", status_for(Some(100), false)); println!("{}", status_for(Some(100), true));}Output:
fullopenclosedfullopenMatch guards are explained in Match guards: adding an if.
Where you’ll usually see it
Section titled “Where you’ll usually see it”After a unit variant gets a value. Event::Logout used to be a unit variant, and you changed it to Logout(u64). Every Event::Logout => arm now gives E0532. Fix: Event::Logout(_) =>, or Event::Logout(at) => if you need the value.
Checking only the kind of a value. Coming from Java or TypeScript, you might write if let Shape::Circle = shape to ask “is it a circle?”. Write if let Shape::Circle(_) = shape, or matches!(shape, Shape::Circle(_)) for a quick bool.
Without the Shape:: prefix it’s E0530. If you write a bare name, like Ok => or Circle => after use Shape::*;, rustc reads it as a new variable. It reports E0530, match bindings cannot shadow tuple variants, with the help try specify the pattern arguments: `Ok(..)` . Same fix: add the parentheses.
Related errors
Section titled “Related errors”- E0533: expected unit struct, unit variant or constant, found struct variant: the same mistake for variants with named fields; add
{ .. }. - E0164: expected tuple struct or tuple variant, found struct variant: parentheses on a variant with named fields, or on an associated constant or function.
- E0023: wrong number of fields in a tuple pattern: the parentheses are right, but you gave too many or too few names.
- E0026: struct or variant does not have a field named x: a wrong field name inside a pattern’s braces.
- E0004: non-exhaustive patterns: after fixing the arms, the
matchstill has to cover every variant. - All compiler errors explained
Quick check
Section titled “Quick check”Quick check
1. For enum Shape { Circle(f64), Empty }, which match arm compiles?
2. rustc says "expected tuple struct or tuple variant, found unit variant Status::Active". What's the fix?
3. struct Point { x: i32, y: i32 }: how do you destructure it with let?
Score: 0 / 3
Read more
Section titled “Read more”- E0532 — Rust error codes index: the official explanation of this error.
- Pattern Syntax — The Rust Book: destructuring structs and enums, ignoring values with
_and.., and match guards. - Destructuring enums — Rust by Example: matching unit and tuple variants side by side.
- Destructuring structs — Rust by Example: braces for named fields, parentheses for tuple structs.
- Patterns — The Rust Reference: the exact rules for path, tuple struct and struct patterns.