Skip to content

fix: friendly onboarding when API key missing#67

Merged
kienbui1995 merged 1 commit intomainfrom
fix/onboarding
Apr 15, 2026
Merged

fix: friendly onboarding when API key missing#67
kienbui1995 merged 1 commit intomainfrom
fix/onboarding

Conversation

@kienbui1995
Copy link
Copy Markdown
Owner

@kienbui1995 kienbui1995 commented Apr 14, 2026

Before:

Error: set ANTHROPIC_API_KEY
Caused by: [MC-E001] missing API key

After:

  ╭─────────────────────────────────────────╮
  │     Welcome to magic-code! 🚀          │
  ╰─────────────────────────────────────────╯

  To get started, set an API key for your LLM provider:

  # Anthropic (default)
  export ANTHROPIC_API_KEY="sk-ant-..."

  # Or use a local model (no API key needed):
  magic-code --provider ollama --model llama3

Summary by CodeRabbit

Bug Fixes

  • Improved CLI error handling to detect missing API credentials during initialization
  • Displays welcome message with environment variable configuration examples when API credentials are not found
  • Gracefully exits with appropriate error code for credential-related failures
  • Maintains existing error reporting behavior for other initialization issues

Before: cryptic 'Error: set ANTHROPIC_API_KEY [MC-E001]'
After: welcome box with setup instructions for all providers

Shows:
- Anthropic, OpenAI, Gemini, Groq, OpenRouter examples
- Local model option (ollama, no key needed)
- Persist hint (~/.bashrc)
- Docs link
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

The CLI's provider initialization now captures provider creation failures and checks for missing API key errors. When detected, it displays a welcome message with environment variable setup instructions and exits cleanly with code 1, instead of propagating raw errors.

Changes

Cohort / File(s) Summary
Provider Initialization Error Handling
mc/crates/mc-cli/src/main.rs
Added explicit error capturing and conditional handling for provider creation. On missing API key errors, constructs debug string, checks for specific substrings/codes, and displays a multi-line welcome message with environment setup examples before exiting with code 1. Non-matching errors are propagated normally.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A missing key no longer stumbles,
The CLI now gently guides and rumbles,
"Welcome, dear user!" it warmly chants,
With env vars spelled—give setup a chance! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description demonstrates the before/after improvement but lacks complete alignment with the template structure. Required sections 'Why' (motivation/issue link) and 'How' (implementation details) are missing, and the checklist is absent. Add 'Why' section with issue reference or motivation, 'How' section explaining implementation approach, and complete the checklist items to confirm testing was performed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: friendly onboarding when API key missing' accurately describes the main change: improving the user experience with a friendly onboarding message when the API key is missing, which aligns with the changeset modifications to error handling in main.rs.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/onboarding

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a user-friendly onboarding message that displays when a required LLM API key is missing, providing setup instructions for various providers. The review feedback suggests refining the error detection logic to prevent the message from appearing for invalid or expired keys, refactoring the extensive print statements into a dedicated helper function to improve code readability in the main function, and removing a redundant type conversion.

Comment on lines +220 to +223
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")
|| err_str.contains("API_KEY")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The check err_str.contains("API_KEY") is too broad. It will likely trigger the onboarding message for other errors, such as an invalid or expired key (e.g., [MC-E003] api error 401: Invalid API_KEY), which should be shown as a standard error to the user rather than a welcome message. Relying on the specific error code MC-E001 or the variant name MissingApiKey is more robust.

Suggested change
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")
|| err_str.contains("API_KEY")
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")

Comment on lines +225 to +248
eprintln!();
eprintln!(" ╭─────────────────────────────────────────╮");
eprintln!(" │ Welcome to magic-code! 🚀 │");
eprintln!(" ╰─────────────────────────────────────────╯");
eprintln!();
eprintln!(" To get started, set an API key for your LLM provider:");
eprintln!();
eprintln!(" # Anthropic (default)");
eprintln!(" export ANTHROPIC_API_KEY=\"sk-ant-...\"");
eprintln!();
eprintln!(" # Or use another provider:");
eprintln!(" export OPENAI_API_KEY=\"sk-...\" # then: magic-code --provider openai");
eprintln!(" export GEMINI_API_KEY=\"...\" # then: magic-code --provider gemini");
eprintln!(
" export GROQ_API_KEY=\"gsk_...\" # then: magic-code --provider groq"
);
eprintln!(" export OPENROUTER_API_KEY=\"sk-or-...\" # then: magic-code --provider openrouter");
eprintln!();
eprintln!(" # Or use a local model (no API key needed):");
eprintln!(" magic-code --provider ollama --model llama3");
eprintln!();
eprintln!(" Add to ~/.bashrc or ~/.zshrc to persist.");
eprintln!(" Docs: https://github.com/kienbui1995/mc-code#install");
eprintln!();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This large block of eprintln! calls clutters the main function. Consider refactoring this onboarding message into a dedicated helper function to keep the high-level logic in main clean and focused.

eprintln!();
std::process::exit(1);
}
return Err(e.into());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The call to .into() is redundant here because e is already an anyhow::Error and the function returns anyhow::Result<()>.

Suggested change
return Err(e.into());
return Err(e);

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mc/crates/mc-cli/src/main.rs (1)

209-214: ⚠️ Potential issue | 🟡 Minor

Treat empty --api-key values as missing before provider creation.

Right now cli.api_key.as_deref() passes Some("") through. For the OpenAI/Groq/OpenRouter constructors in mc/crates/mc-cli/src/provider.rs, that is considered “set”, so magic-code --api-key "" skips the env fallback and never reaches this new onboarding flow.

🛠️ Small normalization
     let primary = provider::create_provider(
         &provider_name,
         &config.provider_config,
         cli.base_url.as_deref(),
-        cli.api_key.as_deref(),
+        cli.api_key.as_deref().filter(|key| !key.is_empty()),
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-cli/src/main.rs` around lines 209 - 214, The call to
provider::create_provider is passing cli.api_key.as_deref() which forwards
Some("") as a set API key; normalize empty strings to None before provider
creation by converting cli.api_key.as_deref() into an Option that returns None
for empty strings (e.g., use .and_then / .filter on the Option<&str> to drop "")
and pass that normalized option into provider::create_provider so empty
--api-key values trigger env fallback and onboarding logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@mc/crates/mc-cli/src/main.rs`:
- Around line 209-214: The call to provider::create_provider is passing
cli.api_key.as_deref() which forwards Some("") as a set API key; normalize empty
strings to None before provider creation by converting cli.api_key.as_deref()
into an Option that returns None for empty strings (e.g., use .and_then /
.filter on the Option<&str> to drop "") and pass that normalized option into
provider::create_provider so empty --api-key values trigger env fallback and
onboarding logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 293dd334-2124-4c9c-aae1-05254f3fe8ba

📥 Commits

Reviewing files that changed from the base of the PR and between 87c57fd and bda4d3b.

📒 Files selected for processing (1)
  • mc/crates/mc-cli/src/main.rs

Comment on lines +216 to +249
let primary = match primary {
Ok(p) => p,
Err(e) => {
let err_str = format!("{e:?}"); // Debug format includes full chain
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")
|| err_str.contains("API_KEY")
{
eprintln!();
eprintln!(" ╭─────────────────────────────────────────╮");
eprintln!(" │ Welcome to magic-code! 🚀 │");
eprintln!(" ╰─────────────────────────────────────────╯");
eprintln!();
eprintln!(" To get started, set an API key for your LLM provider:");
eprintln!();
eprintln!(" # Anthropic (default)");
eprintln!(" export ANTHROPIC_API_KEY=\"sk-ant-...\"");
eprintln!();
eprintln!(" # Or use another provider:");
eprintln!(" export OPENAI_API_KEY=\"sk-...\" # then: magic-code --provider openai");
eprintln!(" export GEMINI_API_KEY=\"...\" # then: magic-code --provider gemini");
eprintln!(
" export GROQ_API_KEY=\"gsk_...\" # then: magic-code --provider groq"
);
eprintln!(" export OPENROUTER_API_KEY=\"sk-or-...\" # then: magic-code --provider openrouter");
eprintln!();
eprintln!(" # Or use a local model (no API key needed):");
eprintln!(" magic-code --provider ollama --model llama3");
eprintln!();
eprintln!(" Add to ~/.bashrc or ~/.zshrc to persist.");
eprintln!(" Docs: https://github.com/kienbui1995/mc-code#install");
eprintln!();
std::process::exit(1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve machine-readable failures when --json is set.

--json is documented for automation/scripting, but this branch always prints a human-only banner and exits. That breaks callers expecting structured output on auth failures.

⚙️ Minimal guard
     let primary = match primary {
         Ok(p) => p,
         Err(e) => {
+            if cli.json {
+                return Err(e.into());
+            }
             let err_str = format!("{e:?}"); // Debug format includes full chain
             if err_str.contains("MC-E001")
                 || err_str.contains("missing API key")
                 || err_str.contains("MissingApiKey")
                 || err_str.contains("API_KEY")

@kienbui1995 kienbui1995 merged commit fa58554 into main Apr 15, 2026
16 checks passed
@kienbui1995 kienbui1995 deleted the fix/onboarding branch April 15, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant