vxcontrol/pentagi · error

command execution timeout (%v). Partial output: %s. HINT: If

Error message

command execution timeout (%v). Partial output: %s. HINT: If this is an interactive command (shell/REPL/listener), use detach=true. For long batch commands, wrap with shell timeout utility: 'timeout %d <command>' to ensure clean completion

What it means

Raised when the exec command does not finish within the configured timeout (the parent context deadline). The library returns any partial output collected so far plus an actionable HINT telling the caller to use detach=true for interactive commands or wrap long batch commands with the shell 'timeout' utility for clean completion.

Source

Thrown at backend/pkg/tools/terminal.go:298

	go func() {
		_, copyErr := io.Copy(&dst, resp.Reader)
		errChan <- copyErr
	}()

	select {
	case err := <-errChan:
		if err != nil && err != io.EOF {
			return "", fmt.Errorf("failed to copy output: %w", err)
		}
	case <-ctx.Done():
		// Close the response to unblock io.Copy
		resp.Close()

		// Wait for the copy goroutine to finish
		<-errChan

		suggestedTimeout := max(int(timeout.Seconds())-10, 10)
		return "", fmt.Errorf(
			"command execution timeout (%v). Partial output: %s. "+
				"HINT: If this is an interactive command (shell/REPL/listener), use detach=true. "+
				"For long batch commands, wrap with shell timeout utility: 'timeout %d <command>' to ensure clean completion",
			ctx.Err(),
			truncateString(dst.String(), 500),
			suggestedTimeout,
		)
	}

	// wait for the exec process to finish
	_, err = t.dockerClient.ContainerExecInspect(ctx, id)
	if err != nil {
		return "", fmt.Errorf("failed to inspect exec process: %w", err)
	}

	results := dst.String()
	// Style system output with color coding
	styledOutput := fmt.Sprintf("%s%s%s%s", ansiColorSystemMsg, results, ansiColorReset, ansiLineTerminator)

View on GitHub (pinned to ea665308ba)

Solutions

  1. Re-run with detach=true for interactive or very long commands, then poll results
  2. Prefix the command with the shell timeout utility, e.g. 'timeout 120 nmap ...'
  3. Increase the timeout argument passed to ExecCommand if the command legitimately needs longer
  4. Use the suggestedTimeout value embedded in the error message as a guide (timeout-10s, min 10s)

Example fix

// before
out, err := term.ExecCommand(ctx, flowID, "nmap -sV -p- target", false)
// after
out, err := term.ExecCommand(ctx, flowID, "timeout 300 nmap -sV -p- target", false)
// or for interactive: term.ExecCommand(ctx, flowID, "bash -i", true)
Defensive patterns

Strategy: validation

Validate before calling

// pick a timeout comfortably above the command's expected runtime
const cmdTimeout = 5 * time.Minute
// wrap long batch commands instead of relying on the exec timeout:
wrapped := fmt.Sprintf("timeout %d %s", int(cmdTimeout.Seconds()), cmd)
_, err := term.ExecCommand(ctx, flowID, wrapped, false)

Try / catch

out, err := term.ExecCommand(ctx, flowID, cmd, false)
if err != nil && strings.Contains(err.Error(), "command execution timeout") {
    // partial output is embedded in the message; decide: detach re-run or longer timeout
    return handleTimeout(err)
}

Prevention

When it happens

Trigger: ExecCommand → getExecResult: ctx.Done() fires while waiting on errChan because the command ran longer than the timeout passed to ExecCommand (interactive shells, REPLs, listeners, or long scans).

Common situations: Running nmap/burp/long brute-force scans past the timeout; accidentally starting an interactive shell (bash, python REPL) or a network listener without detach=true; forgetting the container has no built-in command timeout.

Understand the failure class

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/d04a0c75695c7f14. Report an issue: GitHub.