Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: improve error message when local replica not running #3973

Merged
merged 2 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# UNRELEASED

### chore: improve error message when trying to use the local replica when it is not running

### Frontend canister

Allow setting permissions lists in init arguments just like in upgrade arguments.
Expand Down
10 changes: 10 additions & 0 deletions e2e/tests-dfx/error_context.bash
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,13 @@ teardown() {
assert_contains "it did not contain a function that dfx was looking for"
assert_contains "dfx identity set-wallet <PRINCIPAL> --identity <IDENTITY>"
}

@test "Local replica not running has nice error messages" {
dfx_new
assert_command_fail dfx ping local
assert_contains "You are trying to connect to the local replica but dfx cannot connect to it."
assert_command_fail dfx deploy
assert_contains "You are trying to connect to the local replica but dfx cannot connect to it."
assert_command_fail dfx canister call um5iw-rqaaa-aaaaq-qaaba-cai some_method
assert_contains "You are trying to connect to the local replica but dfx cannot connect to it."
}
42 changes: 42 additions & 0 deletions src/dfx/src/lib/diagnosis.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::lib::error_code;
use anyhow::Error as AnyhowError;
use dfx_core::error::root_key::FetchRootKeyError;
use ic_agent::agent::{RejectCode, RejectResponse};
use ic_agent::AgentError;
use ic_asset::error::{GatherAssetDescriptorsError, SyncError, UploadContentError};
Expand Down Expand Up @@ -55,6 +56,10 @@ pub fn diagnose(err: &AnyhowError) -> Diagnosis {
}
}

if local_replica_not_running(err) {
return diagnose_local_replica_not_running();
}

if let Some(sync_error) = err.downcast_ref::<SyncError>() {
if duplicate_asset_key_dist_and_src(sync_error) {
return diagnose_duplicate_asset_key_dist_and_src();
Expand All @@ -64,6 +69,32 @@ pub fn diagnose(err: &AnyhowError) -> Diagnosis {
NULL_DIAGNOSIS
}

fn local_replica_not_running(err: &AnyhowError) -> bool {
let maybe_agent_error = {
if let Some(FetchRootKeyError::AgentError(agent_error)) =
err.downcast_ref::<FetchRootKeyError>()
{
Some(agent_error)
} else {
err.downcast_ref::<AgentError>()
}
};
if let Some(AgentError::TransportError(transport_error)) = maybe_agent_error {
transport_error.is_connect()
&& transport_error
.url()
.and_then(|url| url.host())
.map(|host| match host {
url::Host::Domain(domain) => domain == "localhost",
url::Host::Ipv4(ipv4_addr) => ipv4_addr.is_loopback(),
url::Host::Ipv6(ipv6_addr) => ipv6_addr.is_loopback(),
})
.unwrap_or(false)
} else {
false
}
}

fn not_a_controller(err: &AgentError) -> bool {
// Newer replicas include the error code in the reject response.
if matches!(
Expand Down Expand Up @@ -119,6 +150,17 @@ The most common way this error is solved is by running 'dfx canister update-sett
)
}

fn diagnose_local_replica_not_running() -> Diagnosis {
let error_explanation =
"You are trying to connect to the local replica but dfx cannot connect to it.";
let action_suggestion =
"Target a different network or run 'dfx start' to start the local replica.";
(
Some(error_explanation.to_string()),
Some(action_suggestion.to_string()),
)
}

fn subnet_not_authorized() -> Diagnosis {
let action_suggestion = "If you are connecting to a node directly instead of a boundary node, try using --provisional-create-canister-effective-canister-id with a canister id in the subnet's canister range. First non-root subnet: 5v3p4-iyaaa-aaaaa-qaaaa-cai, second non-root subnet: jrlun-jiaaa-aaaab-aaaaa-cai";
(None, Some(action_suggestion.to_string()))
Expand Down
Loading