Skip to content

fix(feedback): surface provider binary + error when Send Feedback spawn fails#1067

Open
pedramamini wants to merge 1 commit into
rcfrom
fix/1064-feedback-codex-spawn-error
Open

fix(feedback): surface provider binary + error when Send Feedback spawn fails#1067
pedramamini wants to merge 1 commit into
rcfrom
fix/1064-feedback-codex-spawn-error

Conversation

@pedramamini

@pedramamini pedramamini commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

closes #1064

Problem

Send Feedback auto-selects the first detected supported provider, then FeedbackConversationManager spawns agent.path || agent.command. When the wrong Codex binary gets picked among multiple installs (a codex-multi-auth-codex wrapper, or a shadowed nvm install that isn't authenticated), the spawn exits non-zero and the user only saw a generic "Something went wrong processing your message" / "Something went wrong. Please try again." with no clue which binary ran or why it failed.

Fix

Make every provider-startup failure in the feedback flow actionable:

  • Non-zero exit now reports the resolved binary path plus the provider's own output (auth errors, command not found, stack traces), distilled by a new summarizeProcessFailure() helper (strips ANSI, keeps the meaningful tail). Falls back to a multi-install hint when the binary produced no output.
  • Detected-but-not-runnable and not-found throws now name the resolved binary path.
  • FeedbackChatView's catch block renders the real error message instead of swallowing it behind the generic string.

This directly covers the issue's acceptance criterion: "If provider startup fails, the feedback UI shows the selected binary path and the underlying spawn/auth error instead of only 'Something went wrong.'"

Scope note

This PR addresses the error-surfacing half of the issue, which is independently shippable. The remaining acceptance criteria (feedback consuming a persisted/selected provider path when several Codex installs exist) depend on the multiple-install chooser in #1050 / #1048; once that lands, the feedback path should read the persisted selection. Flagged so that work explicitly covers this flow too.

Testing

  • New src/__tests__/renderer/services/feedbackConversation.test.ts covering the multi-install Codex scenario: spawn uses the resolved binary, non-zero exit surfaces the path + provider output, empty-output failures still name the binary, and unavailable providers throw with the path (and are never spawned).
  • Existing FeedbackChatView tests still pass (10 tests total).
  • npm run lint (tsc, all configs) and ESLint clean on changed files.

Branch base

Targets rc because the inline-feedback chat feature lives on rc, not main.

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced error handling in feedback assistant with more informative failure messages displaying the provider binary path and actual error details instead of generic fallbacks.
    • Improved diagnostics when the chat provider is unavailable or fails to initialize.
  • Tests

    • Added comprehensive test coverage for feedback provider startup failure scenarios and error handling behavior.

Send Feedback showed a generic "Something went wrong" when the
auto-selected provider failed to start. This is common with multiple
Codex installs where the wrong binary (a codex-multi-auth wrapper or a
shadowed nvm install) gets picked and can't run.

The failure message now names the resolved binary path and includes the
provider's own output (auth errors, "command not found", etc.) so the
cause is actionable instead of opaque. The detected-but-not-runnable and
not-found paths also report the resolved binary.

Refs #1064
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR enhances the feedback conversation manager to provide actionable error messages when the AI provider fails. It computes and includes the resolved binary path in errors, captures and summarizes provider output, and ensures the UI displays diagnostic details instead of generic fallback messages.

Changes

Feedback Provider Error Diagnostics

Layer / File(s) Summary
Provider failure diagnostics in service
src/renderer/services/feedbackConversation.ts
Adds summarizeProcessFailure() helper to sanitize and truncate provider output, computes resolved binaryPath from Maestro agent config, updates provider availability and spawn failure handlers to include binary path and formatted output/exit details in error messages, and configures spawn to use the computed binary path.
UI error message display
src/renderer/components/FeedbackChatView.tsx
Updates error handler to extract and show error.message from caught Error objects, displaying diagnostic details to users instead of a generic fallback when provider startup fails.
Test coverage for provider failures
src/__tests__/renderer/services/feedbackConversation.test.ts
Comprehensive Vitest suite mocking window.maestro process events to validate that provider startup failures (stderr+exit code, exit without output, unavailable provider) produce error messages containing resolved binary path and relevant diagnostic detail rather than generic messages.

Sequence Diagram

sequenceDiagram
  participant FeedbackChatView
  participant FeedbackConversationManager
  participant MaestroAgent
  FeedbackChatView->>FeedbackConversationManager: sendMessage()
  FeedbackConversationManager->>FeedbackConversationManager: resolve binaryPath from agent.path or agent.command
  alt Agent not runnable
    FeedbackConversationManager->>FeedbackConversationManager: throw error with resolved binaryPath
    FeedbackConversationManager-->>FeedbackChatView: rejected Promise
  else Spawn process
    FeedbackConversationManager->>MaestroAgent: spawn(binaryPath)
    alt Process exits non-zero
      MaestroAgent-->>FeedbackConversationManager: onExit(code)
      FeedbackConversationManager->>FeedbackConversationManager: summarizeProcessFailure(output)
      FeedbackConversationManager->>FeedbackConversationManager: build error with binaryPath + code + output tail
      FeedbackConversationManager-->>FeedbackChatView: rejected Promise
    else Success
      MaestroAgent-->>FeedbackConversationManager: onData, onExit(0)
      FeedbackConversationManager-->>FeedbackChatView: resolved Promise
    end
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

ready to merge

Poem

🐰 When feedback flows meet binary paths so clear,
Error messages whisper what users need to hear.
No more generic "oops!" in the UI night—
Just resolved binaries shining bright! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 describes the main fix: surfacing provider binary path and error details when Send Feedback provider spawn fails.
Linked Issues check ✅ Passed Changes successfully address #1064 core requirements: surface provider binary path and underlying error instead of generic message, improve error clarity for multi-install scenarios, and add test coverage.
Out of Scope Changes check ✅ Passed All changes are scoped to error surfacing and feedback reliability; provider path persistence (later work in #1050/#1048) is explicitly deferred as out-of-scope.

✏️ 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/1064-feedback-codex-spawn-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jun 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR improves the feedback chat UX when a provider binary fails to start. Previously, all spawn failures resolved with a generic "Something went wrong" string; now they surface the resolved binary path and the provider's own stderr output (via the new summarizeProcessFailure helper), and pre-spawn errors thrown before the Promise are also shown verbatim in the chat rather than swallowed.

  • feedbackConversation.ts: captures binaryPath = agent.path || agent.command before spawning, uses it in all three failure paths (not-found throw, not-available throw, non-zero exit resolve), and adds summarizeProcessFailure() to strip ANSI and keep the actionable tail of provider output.
  • FeedbackChatView.tsx: the catch block in sendMessage now reads error.message instead of hardcoding the generic fallback, so thrown provider errors (unavailable/not-found) reach the user unchanged.
  • New test file covers the full non-zero exit + binary surfacing scenario, the silent-exit fallback, and the not-available throw path.

Confidence Score: 4/5

Safe to merge; the changes are narrow, additive error-surfacing improvements with good test coverage and no modifications to the happy path.

The non-zero exit path now builds a Markdown string that embeds provider output raw inside a fenced code block. If the stderr contains triple-backtick sequences the block breaks, causing cosmetic rendering issues in the chat UI. Separately, binaryPath can silently be undefined when an agent object has neither path nor command, which would show the literal string "undefined" in every new error template — an edge case newly exposed by this PR's richer messages. Both are low-probability issues, but they affect the primary error-surfacing output this PR is designed to improve.

src/renderer/services/feedbackConversation.ts — specifically the detail embedding on line 308 and the binaryPath fallback on line 239.

Important Files Changed

Filename Overview
src/renderer/services/feedbackConversation.ts Adds binaryPath capture, summarizeProcessFailure() helper, and richer error messages for non-zero exit, unavailable, and not-found provider failures.
src/renderer/components/FeedbackChatView.tsx Single-line change: catch block now extracts and displays the real Error.message instead of swallowing it behind a generic string.
src/tests/renderer/services/feedbackConversation.test.ts New test suite covering non-zero exit with binary path + output, silent-exit fallback, and unavailable-provider throw; mock pattern mirrors existing test conventions.

Sequence Diagram

sequenceDiagram
    participant UI as FeedbackChatView
    participant Mgr as FeedbackConversationManager
    participant Maestro as window.maestro

    UI->>Mgr: sendMessage(text, history, callbacks)
    Mgr->>Maestro: agents.get(agentType)
    alt agent not found
        Maestro-->>Mgr: null
        Mgr-->>UI: throw Error("provider could not be found")
        UI->>UI: catch → display error.message in chat
    else agent not available
        Maestro-->>Mgr: "{available: false, path, command}"
        Mgr-->>UI: "throw Error("binary=binaryPath, not runnable")"
        UI->>UI: catch → display error.message in chat
    else agent available
        Maestro-->>Mgr: "{available: true, path, command}"
        Note over Mgr: binaryPath = agent.path || agent.command
        Mgr->>Maestro: "process.spawn({command: binaryPath, ...})"
        loop data events
            Maestro-->>Mgr: onData(sid, chunk)
            Mgr->>Mgr: "outputBuffer += chunk"
        end
        Maestro-->>Mgr: onExit(sid, code)
        alt "code === 0"
            Mgr->>Mgr: extractJsonFromOutput(outputBuffer)
            Mgr-->>UI: resolve(parsedResponse)
            UI->>UI: display response.message in chat
        else "code !== 0"
            Mgr->>Mgr: summarizeProcessFailure(outputBuffer)
            Note over Mgr: strips ANSI, keeps last 8 lines up to 600 chars
            Mgr-->>UI: "resolve({message: binary + output detail})"
            UI->>UI: display error message with binary + output in chat
        end
    end
Loading

Reviews (1): Last reviewed commit: "fix(feedback): surface provider binary +..." | Re-trigger Greptile

// The binary Maestro resolved for this provider. Surfaced in every
// failure path below so the user can tell which install was used -
// critical when multiple Codex binaries (incl. wrappers) are present.
const binaryPath = agent.path || agent.command;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 binaryPath can be undefined when both path and command are absent

agent.path || agent.command resolves to undefined if neither field is populated. The value flows into the spawn command field (likely a pre-existing crash) and, newly in this PR, into every error-message template — so users would see "binary to \"undefined\"" or "Binary: \undefined`". A narrow guard here would make the fallback explicit: agent.path || agent.command || this.agentType`.

`The ${agent.name || this.agentType} provider exited with code ${code} before it could respond.\n\n` +
`**Binary:** \`${binaryPath}\`\n\n` +
(detail
? `**Output:**\n\n\`\`\`\n${detail}\n\`\`\``

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Triple-backtick in provider output breaks the fenced code block

detail is inserted verbatim into a ``` fence. If the provider's stderr contains a triple-backtick sequence (e.g. a CLI printing a Markdown-formatted help text, or a stack trace that quotes a code block), the fence is closed prematurely and MarkdownRenderer renders the remainder as raw Markdown. detail.replace(/```/g, '\\\\\')` before embedding it would prevent the malformed output.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/components/FeedbackChatView.tsx`:
- Around line 358-373: The catch block in FeedbackChatView.tsx that handles
errors from the managerRef.current.sendMessage flow should report the error to
Sentry before updating UI; import and call captureException (from
src/utils/sentry.ts) with the caught error at the top of that catch, then
continue to setMessages with the user-facing detail as currently
implemented—this mirrors the error reporting used in agentDetect and
startConversation and ensures exceptions are visible in production.
🪄 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: Pro

Run ID: 1c678444-8175-4686-94e9-47aad149bc25

📥 Commits

Reviewing files that changed from the base of the PR and between d67c140 and 506abac.

📒 Files selected for processing (3)
  • src/__tests__/renderer/services/feedbackConversation.test.ts
  • src/renderer/components/FeedbackChatView.tsx
  • src/renderer/services/feedbackConversation.ts

Comment on lines +358 to 373
} catch (error) {
// Surface the real reason (e.g. provider binary not found / not
// runnable, with its resolved path) rather than a generic message,
// so multi-install / auth problems are actionable.
const detail =
error instanceof Error && error.message
? error.message
: 'Something went wrong. Please try again.';
setMessages((prev) => [
...prev,
{
role: 'assistant',
content: 'Something went wrong. Please try again.',
content: detail,
timestamp: Date.now(),
},
]);

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 | ⚡ Quick win

Report the caught error to Sentry before surfacing it.

This catch now renders error.message to the user but never reports it. Unexpected failures from managerRef.current.sendMessage are silently swallowed here, unlike the sibling handlers agentDetect (Line 201) and startConversation (Line 307), which both call captureException. Add the same reporting so production breakage stays visible while still showing the actionable detail.

🛡️ Proposed fix
 		} catch (error) {
+			// Report so unexpected provider/runtime failures stay visible in
+			// production, while still surfacing an actionable detail to the user.
+			captureException(error, { extra: { source: 'FeedbackChatView.sendMessage' } });
 			// Surface the real reason (e.g. provider binary not found / not
 			// runnable, with its resolved path) rather than a generic message,
 			// so multi-install / auth problems are actionable.
 			const detail =
 				error instanceof Error && error.message
 					? error.message
 					: 'Something went wrong. Please try again.';

As per coding guidelines: "Do not silently swallow errors. Let unhandled exceptions bubble up to Sentry... Use Sentry utilities (captureException, captureMessage) from src/utils/sentry.ts."

📝 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
} catch (error) {
// Surface the real reason (e.g. provider binary not found / not
// runnable, with its resolved path) rather than a generic message,
// so multi-install / auth problems are actionable.
const detail =
error instanceof Error && error.message
? error.message
: 'Something went wrong. Please try again.';
setMessages((prev) => [
...prev,
{
role: 'assistant',
content: 'Something went wrong. Please try again.',
content: detail,
timestamp: Date.now(),
},
]);
} catch (error) {
// Report so unexpected provider/runtime failures stay visible in
// production, while still surfacing an actionable detail to the user.
captureException(error, { extra: { source: 'FeedbackChatView.sendMessage' } });
// Surface the real reason (e.g. provider binary not found / not
// runnable, with its resolved path) rather than a generic message,
// so multi-install / auth problems are actionable.
const detail =
error instanceof Error && error.message
? error.message
: 'Something went wrong. Please try again.';
setMessages((prev) => [
...prev,
{
role: 'assistant',
content: detail,
timestamp: Date.now(),
},
]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/components/FeedbackChatView.tsx` around lines 358 - 373, The
catch block in FeedbackChatView.tsx that handles errors from the
managerRef.current.sendMessage flow should report the error to Sentry before
updating UI; import and call captureException (from src/utils/sentry.ts) with
the caught error at the top of that catch, then continue to setMessages with the
user-facing detail as currently implemented—this mirrors the error reporting
used in agentDetect and startConversation and ensures exceptions are visible in
production.

@chr1syy

chr1syy commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Review — PR #1067

Reviewed end-to-end against issue #1064 and the bot feedback. Net read: clean, narrow, scope-disciplined regression fix. CI green, mergeable, base rc correct (inline-feedback chat lives only on rc, issue was filed against 0.16.18-RC). Test coverage for the three failure modes is included.

One concrete change requested, two nice-to-haves seconded from Greptile.

🟠 Should fix before merge — Sentry parity in the new catch block

FeedbackChatView.tsx:358-373 now surfaces error.message (good!) but never reports the exception. The other two handlers in the same file already do:

  • FeedbackChatView.tsx:201captureException(error, { extra: { source: 'FeedbackChatView.agentDetect' } })
  • FeedbackChatView.tsx:307captureException(error, { extra: { source: 'FeedbackChatView.startConversation' } })

captureException is already imported at line 41, and CLAUDE.md is explicit about not silently swallowing errors ("DO use Sentry utilities for explicit reporting"). Mechanical one-line fix:

```ts
} catch (error) {
captureException(error, { extra: { source: 'FeedbackChatView.sendMessage' } });
const detail = error instanceof Error && error.message
? error.message
: 'Something went wrong. Please try again.';
// ...existing setMessages call
}
```

Without this, the new richer error surface masks production breakage from Sentry — the user sees a useful message in the chat, but you lose the field signal that something broke.

🟡 Nice-to-have — guard `binaryPath` against `undefined`

Seconding Greptile's P2 on feedbackConversation.ts:239. agent.path || agent.command resolves to undefined when both are absent (pre-existing behavior — the previous commandToUse had the same gap). It didn't matter much before; now it shows up verbatim in every user-facing error template as `undefined` / \"undefined\". A third fallback keeps the message sensible:

```ts
const binaryPath = agent.path || agent.command || this.agentType;
```

🟡 Nice-to-have — escape triple-backticks in provider output

Also seconding Greptile on feedbackConversation.ts:308. detail is embedded raw into a fenced block. If the provider stderr contains a sequence (CLI help text, Markdown-formatted error), the fence closes early and MarkdownRenderer renders the remainder as raw Markdown. Cheap to escape at embed time:

```ts
const safeDetail = detail.replace(/```/g, '`​`​`');
// or switch the wrapper to four-backticks
```

Realistic CLIs that hit this: anything that prints a Markdown-formatted --help on error, anything that quotes the source line in a panic/traceback.

Findings I'd skip

Base branch / mergeability

  • ✅ Targets rc correctly — inline-feedback chat is rc-only, issue against 0.16.18-RC
  • MERGEABLE / CLEAN
  • ✅ CI: lint-and-format, test, Greptile, CodeRabbit all green

Nice fix. The Sentry parity is the only thing I'd actually block on; the two P2s are cheap follow-ups in the same area.

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.

2 participants