fix: Include stderr and troubleshooting help in Claude Code errors
When Claude fails to execute, error messages now include: - Captured stderr output from the failed command - Troubleshooting commands to exec into pod and run `claude login` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4354f96351
commit
e9984ebc07
15
changelog/v0.10.12.md
Normal file
15
changelog/v0.10.12.md
Normal file
@ -0,0 +1,15 @@
|
||||
# v0.10.12
|
||||
|
||||
**Released:** 2026-01-29
|
||||
|
||||
## Changes
|
||||
|
||||
fix: Include stderr and troubleshooting help in Claude Code error messages
|
||||
|
||||
When Claude fails to execute, the error now includes:
|
||||
- The actual stderr output from the failed command
|
||||
- Troubleshooting commands to exec into the pod and run `claude login`
|
||||
|
||||
---
|
||||
|
||||
**Image:** `ghcr.io/orchard9/rdev-api:v0.10.12`
|
||||
@ -24,7 +24,7 @@ spec:
|
||||
serviceAccountName: rdev-api
|
||||
containers:
|
||||
- name: rdev-api
|
||||
image: ghcr.io/orchard9/rdev-api:v0.10.11
|
||||
image: ghcr.io/orchard9/rdev-api:v0.10.12
|
||||
imagePullPolicy: Always
|
||||
|
||||
ports:
|
||||
|
||||
@ -131,6 +131,7 @@ func (a *Adapter) Execute(ctx context.Context, req *domain.AgentRequest, handler
|
||||
// Stream and parse output
|
||||
var wg sync.WaitGroup
|
||||
var finalOutput strings.Builder
|
||||
var stderrOutput strings.Builder
|
||||
var parseErr error
|
||||
var resultMsg *StreamMessage
|
||||
|
||||
@ -142,10 +143,10 @@ func (a *Adapter) Execute(ctx context.Context, req *domain.AgentRequest, handler
|
||||
resultMsg, parseErr = a.parseStreamOutput(stdout, handler, &finalOutput)
|
||||
}()
|
||||
|
||||
// Stream stderr as error events
|
||||
// Stream stderr as error events and capture for error message
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
a.streamStderr(stderr, handler)
|
||||
a.streamStderrCapture(stderr, handler, &stderrOutput)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
@ -168,13 +169,17 @@ func (a *Adapter) Execute(ctx context.Context, req *domain.AgentRequest, handler
|
||||
result.ExitCode = 1
|
||||
result.Error = cmdErr
|
||||
}
|
||||
// Include stderr and troubleshooting help in error
|
||||
result.Error = a.buildErrorWithHelp(result.Error, stderrOutput.String(), namespace, podName)
|
||||
} else if parseErr != nil {
|
||||
result.ExitCode = 1
|
||||
result.Error = parseErr
|
||||
result.Error = a.buildErrorWithHelp(parseErr, stderrOutput.String(), namespace, podName)
|
||||
} else if resultMsg != nil && !resultMsg.IsSuccess() {
|
||||
result.ExitCode = 1
|
||||
if resultMsg.Error != "" {
|
||||
result.Error = fmt.Errorf("%s", resultMsg.Error)
|
||||
result.Error = a.buildErrorWithHelp(fmt.Errorf("%s", resultMsg.Error), stderrOutput.String(), namespace, podName)
|
||||
} else {
|
||||
result.Error = a.buildErrorWithHelp(nil, stderrOutput.String(), namespace, podName)
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,8 +279,8 @@ func (a *Adapter) parseStreamOutput(r io.Reader, handler domain.AgentEventHandle
|
||||
return resultMsg, nil
|
||||
}
|
||||
|
||||
// streamStderr reads stderr and emits error events.
|
||||
func (a *Adapter) streamStderr(r io.Reader, handler domain.AgentEventHandler) {
|
||||
// streamStderrCapture reads stderr, emits error events, and captures output.
|
||||
func (a *Adapter) streamStderrCapture(r io.Reader, handler domain.AgentEventHandler, capture *strings.Builder) {
|
||||
scanner := bufio.NewScanner(r)
|
||||
buf := make([]byte, 0, 64*1024)
|
||||
scanner.Buffer(buf, 1024*1024)
|
||||
@ -292,9 +297,43 @@ func (a *Adapter) streamStderr(r io.Reader, handler domain.AgentEventHandler) {
|
||||
Content: line,
|
||||
Stream: "stderr",
|
||||
})
|
||||
|
||||
// Capture stderr for error message (limit to 4KB)
|
||||
if capture.Len() < 4096 {
|
||||
if capture.Len() > 0 {
|
||||
capture.WriteString("\n")
|
||||
}
|
||||
capture.WriteString(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// buildErrorWithHelp creates an error message with stderr output and troubleshooting help.
|
||||
func (a *Adapter) buildErrorWithHelp(err error, stderr, namespace, podName string) error {
|
||||
var msg strings.Builder
|
||||
|
||||
if err != nil {
|
||||
msg.WriteString(err.Error())
|
||||
} else {
|
||||
msg.WriteString("claude command failed")
|
||||
}
|
||||
|
||||
// Include stderr if available
|
||||
if stderr != "" {
|
||||
msg.WriteString("\n\nstderr:\n")
|
||||
msg.WriteString(stderr)
|
||||
}
|
||||
|
||||
// Add troubleshooting help
|
||||
msg.WriteString("\n\n---\nTroubleshooting:\n")
|
||||
msg.WriteString("If Claude is not authenticated, run:\n")
|
||||
fmt.Fprintf(&msg, " kubectl exec -it -n %s %s -- claude login\n", namespace, podName)
|
||||
msg.WriteString("\nTo test Claude manually:\n")
|
||||
fmt.Fprintf(&msg, " kubectl exec -it -n %s %s -- claude -p \"hello\"\n", namespace, podName)
|
||||
|
||||
return fmt.Errorf("%s", msg.String())
|
||||
}
|
||||
|
||||
// Cancel attempts to cancel a running session.
|
||||
func (a *Adapter) Cancel(ctx context.Context, sessionID string) error {
|
||||
a.sessionsMu.Lock()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user