vxcontrol/pentagi · error
command failed: %w: %s
Error message
command failed: %w: %s
What it means
This error wraps a non-zero exit or execution failure from a detached/background command run inside the Docker terminal sandbox. ExecCommand first runs the command with a quick check timeout; if the exec finishes with an error within that window, it combines the underlying error with whatever partial output was captured so the agent/developer sees both cause and context. It is thrown only when the exec result carries an error, e.g. the command exited non-zero or the exec could not complete.
Source
Thrown at backend/pkg/tools/terminal.go:248
TTY: true,
})
if err != nil {
return "", fmt.Errorf("failed to create exec process: %w", err)
}
if detach {
resultChan := make(chan execResult, 1)
detachedCtx := context.WithoutCancel(ctx)
go func() {
output, err := t.getExecResult(detachedCtx, createResp.ID, timeout)
resultChan <- execResult{output: output, err: err}
}()
select {
case result := <-resultChan:
if result.err != nil {
return "", fmt.Errorf("command failed: %w: %s", result.err, result.output)
}
if result.output == "" {
return "Command completed in background with exit code 0", nil
}
return result.output, nil
case <-time.After(defaultQuickCheckTimeout):
return fmt.Sprintf("Command started in background with timeout %s (still running)", timeout), nil
}
}
return t.getExecResult(ctx, createResp.ID, timeout)
}
func (t *terminal) getExecResult(ctx context.Context, id string, timeout time.Duration) (string, error) {
if timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()View on GitHub (pinned to ea665308ba)
Solutions
- Read the wrapped output (%s) — it contains the command's stdout/stderr identifying the real cause
- Fix the underlying command (correct path, install missing tool, fix permissions)
- If the command legitimately returns non-zero (e.g. grep with no match), wrap it: 'cmd || true' or handle the exit code in shell
- If the command is interactive or long-running, re-run with detach=true so it is not judged by the quick check
Example fix
// before result, err := term.ExecCommand(ctx, flowID, "nmap --typo-flag target", false) // after result, err := term.ExecCommand(ctx, flowID, "nmap -sV target || true", false)
Defensive patterns
Strategy: try-catch
Validate before calling
if strings.TrimSpace(cmd) == "" {
return errors.New("command is empty")
}
// prefer commands that tolerate non-zero exits when "not found" is acceptable:
// strings.HasSuffix(cmd, "|| true") Type guard
func isCmdFailedError(err error) bool {
return err != nil && strings.Contains(err.Error(), "command failed:")
} Try / catch
out, err := term.ExecCommand(ctx, flowID, cmd, false)
if err != nil {
var combined string
if isCmdFailedError(err) {
// err wraps exit cause + output; inspect output to decide retry vs fix
combined = err.Error()
}
return fmt.Errorf("exec failed: %w (%s)", err, combined)
} Prevention
- Always read the wrapped output portion of the error — it names the real failure
- Append '|| true' only when non-zero exit is an expected, acceptable outcome
- Use detach=true for interactive or listener commands
- Test commands manually with docker exec before wiring them into automation
When it happens
Trigger: Calling ExecCommand (via the terminal tool Handle) with a command that exits non-zero or fails inside the container, and the result arrives before defaultQuickCheckTimeout elapses. Also triggered when the command's exit status is surfaced as an error in execResult from the goroutine.
Common situations: Running shell commands in the pentest sandbox that reference missing binaries, bad paths, permission-denied files, or scripts that fail; typos in the command; tools that return non-zero on 'no results found'.
Related errors
- failed to stat container path '%s': %w
- failed to create list exec for '%s': %w
- failed to attach list exec for '%s': %w
- failed to inspect list exec for '%s': %w
- list command failed for '%s' with exit code %d: %s
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/1132f0015ac22b62.
Report an issue: GitHub.