Rust Error E0689: Can't Call Method on Ambiguous Numeric Type
E0689 means: you called a method on a number, but Rust doesn’t know yet which kind of number it is. 2 could be an i32, a u8, a u64 and more, and each of those has its own pow method. You just need to tell Rust which one you mean, usually with a few extra characters like 2_i32 or let x: f64. rustc even shows you where to put them. (This page is part of Rust compiler errors explained.)
The error message
Section titled “The error message”error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` --> src/main.rs:2:16 |2 | let kb = 2.pow(10); // ❌ which kind of integer is `2`? | ^^^ |help: you must specify a concrete type for this numeric value, like `i32` |2 | let kb = 2_i32.pow(10); // ❌ which kind of integer is `2`? | ++++This is the program that produces it:
fn main() { let kb = 2.pow(10); // ❌ which kind of integer is `2`? println!("{}", kb);}The same happens with decimals. Here the number is stored in a variable first, so rustc suggests a type for the variable instead:
error[E0689]: can't call method `sqrt` on ambiguous numeric type `{float}` --> src/main.rs:3:18 |3 | let root = x.sqrt(); // ❌ is `x` an f32 or an f64? | ^^^^ |help: you must specify a type for this binding, like `f32` |2 | let x: f32 = 2.0; | +++++fn main() { let x = 2.0; let root = x.sqrt(); // ❌ is `x` an f32 or an f64? println!("{}", root);}What it means
Section titled “What it means”{integer} and {float} are rustc’s way of saying “a number whose exact type I haven’t picked yet”. {integer} is some whole number type (i8 to i128, u8 to u128, isize, usize). {float} is f32 or f64.
The ^^^ points at the method name. A method belongs to a type: there’s an i32::pow, a u64::pow, an f32::sqrt, an f64::sqrt, and so on. They give different results (an i32 can’t hold 2 to the power 40, a u64 can). To call one, Rust has to know the type at that point in the code, and here it doesn’t.
It’s like asking a shop assistant “how much for 2?”. Two what? Two apples and two TVs cost very different amounts. Once you say “2 apples”, the answer is easy.
Why Rust does this
Section titled “Why Rust does this”Rust does have default number types. If nothing else decides, a whole number becomes an i32 and a decimal becomes an f64. See Integers (whole numbers) and Floating-point numbers (decimals).
But that default is a last resort. Rust first reads the rest of the function to see if something else picks the type, for example passing the number to a function that takes a u8. Only at the very end does it fall back to i32 or f64. A method call can’t wait that long: Rust needs to know which pow it is calling before it can check the arguments and the result type. So instead of guessing, it stops and asks you.
This also means that later code doesn’t help. Even let y: u64 = x.pow(10); gives E0689, because Rust has to choose x’s type before it calls pow, and the u64 is only on the result. What helps is giving the number its type before the method call.
How to fix it
Section titled “How to fix it”Fix 1: Add a type suffix to the number
Section titled “Fix 1: Add a type suffix to the number”Choose this when you call a method directly on a literal, like 2.pow(10) or 2.0.sqrt(). Write the type right after the number. The _ is optional and only there to make it readable: 2_i32 and 2i32 are the same.
For decimals, rustc suggests f32, but f64 is Rust’s default and is more precise. Pick f64 unless you have a reason to save memory.
fn main() { let kb = 2_i32.pow(10); // ✅ an i32 let big = 2_u64.pow(40); // ✅ a u64: 2^40 doesn't fit in an i32 let root = 2.0_f64.sqrt(); // ✅ an f64 let dist = (-7_i32).abs(); // ✅ parentheses, because `-` comes before the method call
println!("2^10 = {}", kb); println!("2^40 = {}", big); println!("sqrt(2) = {}", root); println!("|-7| = {}", dist);}Output:
2^10 = 10242^40 = 1099511627776sqrt(2) = 1.4142135623730951|-7| = 7Choose a type that’s big enough for the result. 2_i32.pow(40) compiles, but it overflows and panics in a debug build. See Integer overflow.
Fix 2: Give the variable a type
Section titled “Fix 2: Give the variable a type”Choose this when the number is stored in a variable first, like let x = 2.0;. This is what rustc’s help: line suggests. Add : type after the variable name:
fn main() { let x: f64 = 2.0; // ✅ now x is an f64 println!("{:.3}", x.sqrt());
let side: f64 = 3.5; println!("area = {}", side.powi(2));
let temperature: i32 = -5; println!("{} degrees from zero", temperature.abs());
let base: u64 = 2; let y = base.pow(10); // y is a u64 too println!("{}", y);}Output:
1.414area = 12.255 degrees from zero1024A suffix on the value works just as well: let x = 2.0_f64;. Use whichever you find easier to read. See Type annotations.
Fix 3: Give the loop variable or closure argument a type
Section titled “Fix 3: Give the loop variable or closure argument a type”Choose this when the number comes from a range, like for i in 1..=3 or (1..=5).map(|n| ...). The variable i or n has type {integer}, and there’s no let to annotate. rustc points at the variable:
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` --> src/main.rs:3:26 |2 | for i in 1..=3 { | - you must specify a type for this binding, like `i32`3 | println!("{}", i.pow(2)); | ^^^Put the suffix on one end of the range, or give the closure argument a type:
fn main() { for i in 1..=3_u32 { // ✅ the whole range is u32 now println!("{} squared is {}", i, i.pow(2)); }
// either a suffix on the range... let total: u32 = (1..=5_u32).map(|n| n.pow(2)).sum(); // ...or a type on the closure argument let total2: u32 = (1..=5).map(|n: u32| n.pow(2)).sum(); println!("sum of squares: {} and {}", total, total2);}Output:
1 squared is 12 squared is 43 squared is 9sum of squares: 55 and 55Notice that let total: u32 = ... alone isn’t enough: rustc needs the type of n inside the closure, before it gets to .sum(). One suffix on the range fixes everything.
Where you’ll usually see it
Section titled “Where you’ll usually see it”abs() on a negative number. let x = -5; x.abs() gives can't call method `abs` on ambiguous numeric type `{integer}`. Fix: let x: i32 = -5;. Careful with a suffix on the literal: -5_i32.abs() means -(5_i32.abs()), which is -5. Use parentheses: (-5_i32).abs().
Quick math in main or a test. let area = 3.14 * r * r; works fine, because * is an operator, not a method. The error only appears once you call a method like .sqrt(), .round() or .powi(). Fix: let r: f64 = 2.0;.
A Vec of numbers. With let nums = vec![1, 2, 3];, nums.iter().map(|n| n.pow(2)) gives a different code, E0599, no method named `pow` found for reference `&{integer}`, because n is a reference here. Same fix: vec![1_i32, 2, 3] or let nums: Vec<i32> = vec![1, 2, 3];.
Related errors
Section titled “Related errors”- E0282: type annotations needed: Rust can’t infer a type at all, for example for
Vec::new()or.collect(). The fix is the same idea: name the type. - E0610: primitive type doesn’t have fields:
.somethingwithout()on an{integer}, likex.absinstead ofx.abs(). - E0599: no method named x found: the type is known, but it has no such method, or (as above) it’s a reference to an
{integer}. - E0308: mismatched types: what you might see next, if the type you pick doesn’t match where the number is used.
- All compiler errors explained
Quick check
Section titled “Quick check”Quick check
1. Which line compiles?
2. If nothing else decides, what type does Rust give 7 and 7.0?
3. for i in 0..10 { println!("{}", i.pow(2)); } gives E0689. What's the simplest fix?
Score: 0 / 3
Read more
Section titled “Read more”- E0689 — Rust error codes index: the official explanation of this error.
- Data Types — The Rust Book: integer and float types, number literals with suffixes like
57u8, and thei32/f64defaults. - Literals — Rust by Example: how suffixes like
1u32and1.0f64pick a type. - Integer literal expressions — The Rust Reference: the exact rules for how a literal gets its type, including the
i32fallback. f64::sqrt— Rust standard library: the float methods (sqrt,powi,round…) that need a known type.