Skip to content

Commit 2d4ef29

Browse files
adamspofford-dfinityrikonor
authored andcommitted
Improve error message for bad cycles wallet (#3790)
1 parent 15306eb commit 2d4ef29

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

e2e/tests-dfx/error_context.bash

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,15 @@ teardown() {
199199
assert_command_fail dfx canister status hello_backend
200200
assert_match "not part of the controllers" # this is part of the error explanation
201201
assert_match "'dfx canister update-settings --add-controller <controller principal to add> <canister id/name or --all> \(--network ic\)'" # this is part of the solution
202-
}
202+
}
203+
204+
@test "bad wallet canisters get diagnosed" {
205+
dfx_new hello
206+
dfx_start
207+
dfx deploy hello_backend --no-wallet
208+
id=$(dfx canister id hello_backend)
209+
dfx identity set-wallet "$id" --force
210+
assert_command_fail dfx wallet balance
211+
assert_contains "it did not contain a function that dfx was looking for"
212+
assert_contains "dfx identity set-wallet <PRINCIPAL> --identity <IDENTITY>"
213+
}

src/dfx/src/lib/diagnosis.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub fn diagnose(err: &AnyhowError) -> Diagnosis {
4545
}
4646

4747
if let Some(agent_err) = err.downcast_ref::<AgentError>() {
48+
if wallet_method_not_found(agent_err) {
49+
return diagnose_bad_wallet();
50+
}
4851
if not_a_controller(agent_err) {
4952
return diagnose_http_403();
5053
} else if *agent_err == AgentError::CertificateNotAuthorized() {
@@ -82,6 +85,22 @@ fn not_a_controller(err: &AgentError) -> bool {
8285
matches!(std::str::from_utf8(payload.content.as_slice()), Ok("Wrong sender")))
8386
}
8487

88+
fn wallet_method_not_found(err: &AgentError) -> bool {
89+
match err {
90+
AgentError::CertifiedReject(RejectResponse {
91+
reject_code: RejectCode::CanisterError,
92+
reject_message,
93+
..
94+
}) if reject_message.contains("Canister has no update method 'wallet_") => true,
95+
AgentError::UncertifiedReject(RejectResponse {
96+
reject_code: RejectCode::CanisterError,
97+
reject_message,
98+
..
99+
}) if reject_message.contains("Canister has no query method 'wallet_") => true,
100+
_ => false,
101+
}
102+
}
103+
85104
fn diagnose_http_403() -> Diagnosis {
86105
let error_explanation = "Each canister has a set of controllers. Only those controllers have access to the canister's management functions (like install_code or stop_canister).\n\
87106
The principal you are using to call a management function is not part of the controllers.";
@@ -150,3 +169,21 @@ See also release notes: https://forum.dfinity.org/t/dfx-0-11-0-is-promoted-with-
150169

151170
(Some(explanation.to_string()), Some(suggestion.to_string()))
152171
}
172+
173+
fn diagnose_bad_wallet() -> Diagnosis {
174+
let explanation = "\
175+
A wallet has been previously configured (e.g. via `dfx identity set-wallet`).
176+
However, it did not contain a function that dfx was looking for.
177+
This may be because:
178+
- a wallet was correctly installed, but is outdated
179+
- `dfx identity set-wallet` was used on a non-wallet canister";
180+
let suggestion = "\
181+
If you have had the wallet for a while, then you may need to update it with
182+
`dfx wallet upgrade`. The release notes indicate when there is a new wallet.
183+
If you recently ran `dfx identity set-wallet`, and the canister may have been
184+
wrong, you can set a new wallet with
185+
`dfx identity set-wallet <PRINCIPAL> --identity <IDENTITY>`.
186+
If you're using a local replica and configuring a wallet was a mistake, you can
187+
recreate the replica with `dfx stop && dfx start --clean` to start over.";
188+
(Some(explanation.to_string()), Some(suggestion.to_string()))
189+
}

0 commit comments

Comments
 (0)