Skip to content

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.)

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);
}

{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.

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.

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 = 1024
2^40 = 1099511627776
sqrt(2) = 1.4142135623730951
|-7| = 7
▶ Try it Yourself

Choose 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.

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.414
area = 12.25
5 degrees from zero
1024
▶ Try it Yourself

A 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 1
2 squared is 4
3 squared is 9
sum of squares: 55 and 55
▶ Try it Yourself

Notice 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.

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];.

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