{"record":{"id":"1132f0015ac22b62","repo":"vxcontrol/pentagi","slug":"command-failed-w-s","errorCode":null,"errorMessage":"command failed: %w: %s","messagePattern":"command failed: %w: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/terminal.go","lineNumber":248,"sourceCode":"\t\tTTY:          true,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create exec process: %w\", err)\n\t}\n\n\tif detach {\n\t\tresultChan := make(chan execResult, 1)\n\t\tdetachedCtx := context.WithoutCancel(ctx)\n\n\t\tgo func() {\n\t\t\toutput, err := t.getExecResult(detachedCtx, createResp.ID, timeout)\n\t\t\tresultChan <- execResult{output: output, err: err}\n\t\t}()\n\n\t\tselect {\n\t\tcase result := <-resultChan:\n\t\t\tif result.err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"command failed: %w: %s\", result.err, result.output)\n\t\t\t}\n\t\t\tif result.output == \"\" {\n\t\t\t\treturn \"Command completed in background with exit code 0\", nil\n\t\t\t}\n\t\t\treturn result.output, nil\n\t\tcase <-time.After(defaultQuickCheckTimeout):\n\t\t\treturn fmt.Sprintf(\"Command started in background with timeout %s (still running)\", timeout), nil\n\t\t}\n\t}\n\n\treturn t.getExecResult(ctx, createResp.ID, timeout)\n}\n\nfunc (t *terminal) getExecResult(ctx context.Context, id string, timeout time.Duration) (string, error) {\n\tif timeout > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, timeout)\n\t\tdefer cancel()","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/terminal.go#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","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"],"exampleFix":"// before\nresult, err := term.ExecCommand(ctx, flowID, \"nmap --typo-flag target\", false)\n// after\nresult, err := term.ExecCommand(ctx, flowID, \"nmap -sV target || true\", false)","handlingStrategy":"try-catch","validationCode":"if strings.TrimSpace(cmd) == \"\" {\n    return errors.New(\"command is empty\")\n}\n// prefer commands that tolerate non-zero exits when \"not found\" is acceptable:\n// strings.HasSuffix(cmd, \"|| true\")","typeGuard":"func isCmdFailedError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"command failed:\")\n}","tryCatchPattern":"out, err := term.ExecCommand(ctx, flowID, cmd, false)\nif err != nil {\n    var combined string\n    if isCmdFailedError(err) {\n        // err wraps exit cause + output; inspect output to decide retry vs fix\n        combined = err.Error()\n    }\n    return fmt.Errorf(\"exec failed: %w (%s)\", err, combined)\n}","preventionTips":["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"],"tags":["docker","exec","terminal","command-failed"],"backgroundTag":"command-exit-nonzero","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}