From 8a07dfd634ec0537f36030d3fd9215a1c0b1db98 Mon Sep 17 00:00:00 2001
From: Vincent Zhang <vincent.zhang@dfinity.org>
Date: Tue, 26 Nov 2024 23:30:12 +0800
Subject: [PATCH] Improve error message for 'dfx deploy'.

---
 CHANGELOG.md                 | 11 +++++++++++
 src/dfx/src/lib/diagnosis.rs | 21 +++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5396853a28..0ee339a5df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,17 @@ Added a flag `--replica` to `dfx start`. This flag currently has no effect.
 Once PocketIC becomes the default for `dfx start` this flag will start the replica instead.
 You can use the `--replica` flag already to write scripts that anticipate that change.
 
+### chore: improve `dfx deploy` messages.
+
+If users run `dfx deploy` without enough cycles, show additional messages to indicate what to do next.
+```
+Error explanation:
+Insufficient cycles balance to create the canister.
+How to resolve the error:
+Please top up your cycles balance by converting ICP to cycles like below:
+'dfx cycles convert --amount=0.123 --ic'.
+```
+
 # 0.24.3
 
 ### feat: Bitcoin support in PocketIC
diff --git a/src/dfx/src/lib/diagnosis.rs b/src/dfx/src/lib/diagnosis.rs
index 150f1c9b56..114fb248e1 100644
--- a/src/dfx/src/lib/diagnosis.rs
+++ b/src/dfx/src/lib/diagnosis.rs
@@ -1,3 +1,4 @@
+use crate::lib::cycles_ledger_types::create_canister::CreateCanisterError;
 use crate::lib::error_code;
 use anyhow::Error as AnyhowError;
 use dfx_core::error::root_key::FetchRootKeyError;
@@ -72,6 +73,12 @@ pub fn diagnose(err: &AnyhowError) -> Diagnosis {
         }
     }
 
+    if let Some(_create_canister_err) = err.downcast_ref::<CreateCanisterError>() {
+        if insufficient_cycles(_create_canister_err) {
+            return diagnose_insufficient_cycles();
+        }
+    }
+
     NULL_DIAGNOSIS
 }
 
@@ -262,3 +269,17 @@ fn diagnose_ledger_not_found() -> Diagnosis {
 
     (Some(explanation.to_string()), Some(suggestion.to_string()))
 }
+
+fn insufficient_cycles(err: &CreateCanisterError) -> bool {
+    match err {
+        CreateCanisterError::InsufficientFunds { balance: _ } => true,
+        _ => false,
+    }
+}
+
+fn diagnose_insufficient_cycles() -> Diagnosis {
+    let explanation = "Insufficient cycles balance to create the canister.";
+    let suggestion = "Please top up your cycles balance by converting ICP to cycles like below:
+'dfx cycles convert --amount=0.123 --ic'.";
+    (Some(explanation.to_string()), Some(suggestion.to_string()))
+}