Skip to content

Rust Error E0164: Expected Tuple Struct or Tuple Variant, Found Struct Variant

E0164 means: you wrote parentheses in a pattern, like Shape::Circle(r), after a name that doesn’t take values in parentheses. In today’s Rust you’ll meet it in three situations: an enum variant with named fields (Circle { radius: f64 }) matched as if it were a tuple variant, an associated function like Celsius::new(d) used as a pattern, and an associated constant like Volume::MAX(_) with parentheses after it. Each has a short, clear fix. (This page is part of Rust compiler errors explained.)

error[E0164]: expected tuple struct or tuple variant, found struct variant `Shape::Circle`
--> src/main.rs:8:9
|
8 | Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` has named fields
| ^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
help: the struct variant's field is being ignored
|
8 - Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` has named fields
8 + Shape::Circle { radius: _ } => 3.14 * r * r, // ❌ `Circle` has named fields
|

This is the program that produces it:

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` has named fields
Shape::Square { side } => side * side,
}
}
fn main() {
println!("{}", area(&Shape::Square { side: 2.0 }));
}

The ^^^ covers the whole pattern Shape::Circle(r), and the label says what Rust expected there: “a tuple struct or tuple variant”. Only those two kinds of things are written with parentheses in a pattern, because only they hold values by position, like Some(x) or Meters(m).

Shape::Circle is a struct variant. Its value has a name, radius, and named fields are matched with braces: Shape::Circle { radius }.

Be careful with the help: here. It suggests Shape::Circle { radius: _ }, which fixes the pattern but ignores the radius. Our arm uses r, so copying the suggestion as it is gives a new error, E0425 cannot find value `r` in this scope. When you need the value, give it a name inside the braces, as in Fix 1.

It’s like a form with labelled boxes, “Width: … Height: …”, and you wrote “3, 4” next to the title. The numbers might be right, but the form wants each one in its labelled box.

A pattern has to look like the value it matches. Rust has two ways to hold data, and each has its own pattern (see Enums can hold data):

Defined as Created with Matched with
Circle(f64) (tuple variant) Shape::Circle(1.0) Shape::Circle(r)
Circle { radius: f64 } (struct variant) Shape::Circle { radius: 1.0 } Shape::Circle { radius }

Named fields are matched by name, not by position, so the order in the pattern doesn’t matter and adding a field later doesn’t silently shift the others. Mixing the two styles is refused, so there’s never a question about which value goes where.

Patterns are also checked at compile time, so they can’t run code. That’s why a function name followed by (d) can’t be a pattern either, even when the function builds exactly the value you’re matching. More in Pattern Matching.

Choose this when the message says found struct variant, which is the most common E0164. Write the field name (Rust then makes a variable with that name), field: new_name to pick another name, or { .. } to ignore all fields:

enum Shape {
Circle { radius: f64 },
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ field name in braces
Shape::Rect { w: width, h: height } => width * height, // ✅ field: new name
}
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "circle", // ✅ "any circle"
Shape::Rect { .. } => "rectangle",
}
}
fn main() {
let shapes = [Shape::Circle { radius: 1.0 }, Shape::Rect { w: 2.0, h: 3.0 }];
for shape in &shapes {
println!("{}: {:.2}", name(shape), area(shape));
}
}

Output:

circle: 3.14
rectangle: 6.00
▶ Try it Yourself

If you list some fields but not all, add .. at the end, like Shape::Rect { w, .. }. Leaving it out gives E0027, and a misspelled field name gives E0026.

Fix 2: Turn the variant into a tuple variant

Section titled “Fix 2: Turn the variant into a tuple variant”

Choose this when parentheses really are what you want: the variant has one obvious value, and you’d rather write Shape::Circle(1.0) everywhere. Change the definition, and the Circle(r) pattern becomes correct:

enum Shape {
Circle(f64), // ✅ now a tuple variant: one unnamed value
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ parentheses fit a tuple variant
Shape::Rect { w, h } => w * h,
}
}
fn main() {
let small = Shape::Circle(1.0); // created with parentheses too
let big = Shape::Circle(2.0);
let door = Shape::Rect { w: 1.0, h: 2.0 };
println!("{:.2} {:.2} {:.2}", area(&small), area(&big), area(&door));
}

Output:

3.14 12.56 2.00
▶ Try it Yourself

This changes the type, so every place that creates or matches Circle must switch to parentheses too. The compiler lists each one. For two or more values, named fields are usually clearer.

Fix 3: Match the tuple struct itself, and call functions in a guard

Section titled “Fix 3: Match the tuple struct itself, and call functions in a guard”

Choose this when the message says found associated function and the label says `fn` calls are not allowed in patterns. You wrote a constructor like Celsius::new(d) where Rust needs a pattern:

error[E0164]: expected tuple struct or tuple variant, found associated function `Celsius::new`
--> src/main.rs:11:9
|
11 | Celsius::new(d) if d > 25.0 => "warm", // ❌ `new` is a function, not a pattern
| ^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns

The program behind it:

struct Celsius(f64);
impl Celsius {
fn new(degrees: f64) -> Celsius {
Celsius(degrees)
}
}
fn feels(t: Celsius) -> &'static str {
match t {
Celsius::new(d) if d > 25.0 => "warm", // ❌ `new` is a function, not a pattern
_ => "cool",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
}

Celsius is a tuple struct, so the pattern is the struct’s own name: Celsius(d). Anything that needs a function or method call goes into a match guard (if ... after the pattern):

struct Celsius(f64);
impl Celsius {
fn new(degrees: f64) -> Celsius {
Celsius(degrees)
}
fn is_freezing(&self) -> bool {
self.0 <= 0.0
}
}
fn feels(t: Celsius) -> &'static str {
match t {
Celsius(d) if d > 25.0 => "warm", // ✅ the tuple struct itself, plus a guard
Celsius(_) => "cool",
}
}
fn describe(t: &Celsius) -> &'static str {
match t {
t if t.is_freezing() => "freezing", // ✅ methods go in a guard
_ => "not freezing",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
println!("{}", feels(Celsius::new(12.5)));
let Celsius(d) = Celsius::new(-3.0); // ✅ also works with `let`
println!("{} degrees", d);
println!("{}", describe(&Celsius::new(-3.0)));
}

Output:

warm
cool
-3 degrees
freezing
▶ Try it Yourself

If the struct’s field is private (it lives in another module), you can’t write Celsius(d) outside that module. Then use a getter in a guard, like t if t.degrees() > 25.0. See Match guards: adding an if.

Fix 4: Drop the parentheses after a constant

Section titled “Fix 4: Drop the parentheses after a constant”

Choose this when the message says found associated constant. A constant is already a complete pattern. It matches one exact value, so there’s nothing to put in parentheses:

error[E0164]: expected tuple struct or tuple variant, found associated constant `Volume::MAX`
--> src/main.rs:10:9
|
10 | Volume::MAX(_) => "loudest", // ❌ a constant takes no ()
| ^^^^^^^^^^^^^^ not a tuple struct or tuple variant

The program behind it:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "muted",
Volume::MAX(_) => "loudest", // ❌ a constant takes no ()
_ => "normal",
}
}
fn main() {
println!("{}", label(10));
}

Write the constant on its own:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "muted",
Volume::MAX => "loudest", // ✅ a constant, on its own
1..=3 => "quiet",
_ => "normal",
}
}
fn main() {
for level in [0, 2, 7, 10, u8::MAX] {
println!("{}: {}", level, label(level));
}
}

Output:

0: muted
2: quiet
7: normal
10: loudest
255: normal
▶ Try it Yourself

The same goes for constants from the standard library: u32::MAX(_) is E0164, u32::MAX is a valid pattern.

After switching a variant to named fields. You turned Move(i32, i32) into Move { x: i32, y: i32 } for clarity. Every old Command::Move(x, y) => arm now gives E0164. Fix: Command::Move { x, y } =>.

Matching with a “parser” function. Something like match input { Version::parse(v) => ... }, hoping the function runs while matching. Fix: call it first, then match on the result: match Version::parse(input) { Some(v) => ..., None => ... }.

Free functions, plain structs and unit variants give E0532 instead. The same parentheses mistake is reported as E0532 when the name isn’t reached through a type: a plain function (Some(limit()), expected a pattern, found a function call), a struct with named fields (let Point(x, y) = p;, found struct `Point` ), or a unit variant (Status::Active()). The fixes are the same as on this page.

Quick check

1. For enum Shape { Circle { radius: f64 } }, which arm uses the radius correctly?

2. Celsius::new(d) => ... gives "fn calls are not allowed in patterns". Celsius is struct Celsius(f64);. What pattern works?

3. How do you match the associated constant Volume::MAX?

Score: 0 / 3