How can I tell where an error is coming from with the question mark operator?

I have a function that parses some text input into a struct with multiple fields, including several numeric types, and it returns what is basically a Result<MyStruct, Box<dyn Error>. I use the question mark operator a fair amount when parsing strings into numbers, as well as to convert None into an error when expected input is not found (.ok_or_else(||...)).

I have a test for this parsing function that is failing with a ParseIntError somewhere. Is there any way for me to see what line this error is coming from? Even with RUST_BACKTRACE=full all I'm seeing for src/main.rs are references to the lines of the test, not the lines in the parse function that may be erroring (there are several lines to choose from).

It seems silly, but to debug this my only thought is to go through and replace every ? with .expect("problem at line X") until I can narrow it down.

It just seems surprising to have "proper" error handling seem harder to debug (during development at least) than doing it the "wrong" way with a panic, especially with line numbers now in the panic messages! My assumption is that I'm overlooking something or just plain doing it wrong.

Playground example (choose backtrace under ...).

As far as I can tell no output relevant to the problem being on line 10 (EDIT: now 14) or even related to the problematic function, on MacOS or Linux:

$ RUST_BACKTRACE=full cargo test |& grep \
  -e 'main\.rs' \
  -e 'question' \
  -e 'whups'
                               at src/main.rs:39
thread 'tests::test2' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', src/main.rs:46:20
                               at src/main.rs:46
                               at src/main.rs:44

(Crosslink: tried posting at r/learnrust without much interest.)

1 Like

I understand it's not ideal, but by default errors do not carry a backtrace. You can take a look at this survey and look for a crate that provides a backtrace. You can view the situation on updating this in std here.

Thanks for the link. So sounds like I'm doing it right-ish.

Same Q from that thread: https://github.com/rust-lang/rust/issues/53487#issuecomment-501838694

What I do in my crates is simply attach file/line/column information to my errors (which are enum variants) with the file!(), line!() and column!() macros. That way, if an error is returned I know the precise location in the code that is responsible.

But is this possible with the ? operator? Or do you just not use it?

How would you do this with my example?

This would require changing the code where the error originally came from, and would allow using ? on the way up from there.

Yeah that makes it less than ideal if the ParseIntError is defined in another crate.

What is possible though is printing (with println) output at various stages. This works because anything printed to stdout is actually printed whenever a test fails.
It's far from ideal in terms fo effort, but it'll ultimately yield results.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.