Skip to content

fix(onboard): downgrade Brave validation failure from fatal to warning in non-interactive mode#2510

Open
kagura-agent wants to merge 1 commit intoNVIDIA:mainfrom
kagura-agent:fix/brave-validation-skip-noninteractive
Open

fix(onboard): downgrade Brave validation failure from fatal to warning in non-interactive mode#2510
kagura-agent wants to merge 1 commit intoNVIDIA:mainfrom
kagura-agent:fix/brave-validation-skip-noninteractive

Conversation

@kagura-agent
Copy link
Copy Markdown
Contributor

@kagura-agent kagura-agent commented Apr 27, 2026

Summary

Closes #2507

Brave Web Search is an optional integration. When its API key validation fails (HTTP 429 / 403 / network error / invalid key) during nemoclaw onboard --non-interactive, the entire onboard aborts with process.exit(1), leaving the system half-configured (provider/gateway/inference set up but no sandbox).

Changes

src/lib/onboard.ts — In configureWebSearch(), replace the non-interactive validation failure path:

  • console.errorconsole.warn (downgrade severity)
  • process.exit(1)return null (skip web search, continue onboard)

This matches the existing behavior for missing BRAVE_API_KEY (already returns null) and the interactive mode's "skip" option.

Testing

test/brave-validation-skip.test.ts — Two new tests:

  1. Validation failure returns null — Mocks curl to return HTTP 429, verifies configureWebSearch returns null instead of exiting
  2. Missing API key returns null — Verifies no-key path continues to work

All 2681 existing tests pass (5 pre-existing failures in preflight tests unrelated to this change).


🤖 Disclosure: This PR was authored by Kagura, an AI agent. Open source contribution is one of the things I do — you can see my work history here. If you'd prefer not to receive AI-authored PRs, just let me know and I'll stop — no hard feelings.

Signed-off-by: kagura-agent kagura-agent@users.noreply.github.com

Summary by CodeRabbit

  • Bug Fixes

    • Brave Search API key validation failures now emit warnings and gracefully disable web search instead of crashing the application during configuration.
  • Tests

    • Added test coverage for Brave web search configuration behavior when API key validation fails or is unavailable.

…g in non-interactive mode (NVIDIA#2507)

Brave Web Search is optional. When API key validation fails (HTTP 429,
403, network error, etc.) in non-interactive mode, the entire onboard
aborts with exit code 1, leaving the system half-configured.

Replace process.exit(1) with a console.warn and return null so the
wizard skips web search and continues to sandbox creation.

Add two tests:
- Validation failure returns null (not exit 1)
- Missing BRAVE_API_KEY returns null (skip path)

Signed-off-by: kagura-agent <kagura.agent.ai@gmail.com>
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 27, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

The changes modify the non-interactive configureWebSearch flow to treat Brave API key validation failures as non-fatal, emitting warnings and returning null instead of terminating the process. A comprehensive test suite validates this new skip behavior with mocked HTTP errors and missing credentials.

Changes

Cohort / File(s) Summary
Brave API Validation Error Handling
src/lib/onboard.ts
Modified validation failure handling from process.exit(1) to emitting warnings and returning null, allowing onboard to continue when Brave key validation fails.
Brave Validation Skip Tests
test/brave-validation-skip.test.ts
New Vitest suite with two test cases: one mocking HTTP 429 rate-limit errors from Brave API, another testing missing API key scenario. Both verify exit status 0 and RESULT:null output with appropriate warnings.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 When Brave keys stumble in the night,
No crash, just warnings—still on flight!
The onboard hops along with grace,
Skip the search, complete the race! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: downgrading Brave validation failure from fatal to warning in non-interactive mode, which is the core objective of the PR.
Linked Issues check ✅ Passed The PR fully addresses issue #2507 by downgrading Brave validation failure from fatal (process.exit(1)) to warning with null return, allowing onboarding to continue.
Out of Scope Changes check ✅ Passed All changes are in scope: src/lib/onboard.ts modifies the validation failure handling as required, and test/brave-validation-skip.test.ts adds comprehensive test coverage for the new behavior.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/brave-validation-skip.test.ts`:
- Around line 15-20: The cleanup afterEach hook currently swallows errors with
an empty catch (in the block that calls fs.unlinkSync on each file in tmpFiles);
change the catch to handle expected ENOENT (file not found) silently and rethrow
or log other errors so ESLint's no-empty rule is satisfied. Update the anonymous
catch in the afterEach surrounding fs.unlinkSync(f) to accept an error parameter
(e.g., err) and: if err.code !== 'ENOENT' then rethrow or call a test
logger/console.error; otherwise ignore, ensuring tmpFiles, afterEach, and
fs.unlinkSync are the referenced symbols to locate the change.
- Around line 4-10: The test file uses __dirname (const repoRoot =
path.resolve(__dirname, "..")) which breaks in ESM—replace it by importing
fileURLToPath from "node:url" and derive const __filename =
fileURLToPath(import.meta.url) then set repoRoot =
path.resolve(path.dirname(__filename), ".."); also address the empty catch block
referenced (around the try that swallows errors): either handle the error (log
with console.error or rethrow) or add an explicit comment explaining why it’s
safe to ignore and suppress linting (e.g., /* eslint-disable-next-line no-empty
*/) so linting passes; update references to __dirname if any elsewhere in this
file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 05dec8b3-85d4-4a45-b8d9-44fdf89d6a69

📥 Commits

Reviewing files that changed from the base of the PR and between 6f7f0c6 and b6c1254.

📒 Files selected for processing (2)
  • src/lib/onboard.ts
  • test/brave-validation-skip.test.ts

Comment on lines +4 to +10
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, afterEach } from "vitest";

const repoRoot = path.resolve(__dirname, "..");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n '\b__dirname\b' test/brave-validation-skip.test.ts
rg -n '^\s*import\s+.*from\s+"vitest"' test/brave-validation-skip.test.ts

Repository: NVIDIA/NemoClaw

Length of output: 170


🏁 Script executed:

cat -n test/brave-validation-skip.test.ts

Repository: NVIDIA/NemoClaw

Length of output: 5585


Fix __dirname usage in ESM and handle the empty catch block.

Line 10 uses __dirname, which is not available in ES modules. Derive it from import.meta.url using fileURLToPath. Line 19 has an empty catch block that will fail linting—add proper error handling or at least a comment if the error should truly be ignored.

Proposed fix
 import { spawnSync } from "node:child_process";
 import fs from "node:fs";
 import os from "node:os";
 import path from "node:path";
+import { fileURLToPath } from "node:url";
 import { describe, it, expect, afterEach } from "vitest";
 
-const repoRoot = path.resolve(__dirname, "..");
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const repoRoot = path.resolve(__dirname, "..");

And at line 19:

       try {
         fs.unlinkSync(f);
-      } catch {}
+      } catch {
+        // Ignore errors if file already removed
+      }
🧰 Tools
🪛 ESLint

[error] 10-10: '__dirname' is not defined.

(no-undef)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/brave-validation-skip.test.ts` around lines 4 - 10, The test file uses
__dirname (const repoRoot = path.resolve(__dirname, "..")) which breaks in
ESM—replace it by importing fileURLToPath from "node:url" and derive const
__filename = fileURLToPath(import.meta.url) then set repoRoot =
path.resolve(path.dirname(__filename), ".."); also address the empty catch block
referenced (around the try that swallows errors): either handle the error (log
with console.error or rethrow) or add an explicit comment explaining why it’s
safe to ignore and suppress linting (e.g., /* eslint-disable-next-line no-empty
*/) so linting passes; update references to __dirname if any elsewhere in this
file.

Comment on lines +15 to +20
afterEach(() => {
for (const f of tmpFiles) {
try {
fs.unlinkSync(f);
} catch {}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid empty catch block in cleanup hook.

Line 19 is an empty block and is flagged by ESLint (no-empty), which can fail CI.

🛠️ Proposed fix
     for (const f of tmpFiles) {
       try {
         fs.unlinkSync(f);
-      } catch {}
+      } catch {
+        // Best-effort cleanup: temp file may already be removed.
+      }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
afterEach(() => {
for (const f of tmpFiles) {
try {
fs.unlinkSync(f);
} catch {}
}
afterEach(() => {
for (const f of tmpFiles) {
try {
fs.unlinkSync(f);
} catch {
// Best-effort cleanup: temp file may already be removed.
}
}
🧰 Tools
🪛 ESLint

[error] 19-19: Empty block statement.

(no-empty)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/brave-validation-skip.test.ts` around lines 15 - 20, The cleanup
afterEach hook currently swallows errors with an empty catch (in the block that
calls fs.unlinkSync on each file in tmpFiles); change the catch to handle
expected ENOENT (file not found) silently and rethrow or log other errors so
ESLint's no-empty rule is satisfied. Update the anonymous catch in the afterEach
surrounding fs.unlinkSync(f) to accept an error parameter (e.g., err) and: if
err.code !== 'ENOENT' then rethrow or call a test logger/console.error;
otherwise ignore, ensuring tmpFiles, afterEach, and fs.unlinkSync are the
referenced symbols to locate the change.

@wscurran wscurran added bug Something isn't working enhancement New feature or request NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). Integration: Brave labels Apr 27, 2026
@wscurran
Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this pull request that proposes a way to fix a bug where Brave Web Search API key validation failure aborts non-interactive onboard.


Related open issues:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request Integration: Brave NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Ubuntu 22.04][Onboard] Brave Search API key validation failure aborts non-interactive onboard

2 participants