chatboxai/chatbox · warning · Error
Command is required
Error message
Command is required
What it means
Thrown by executeUserExecCommand() when the command field is missing, empty, or not a string. This is the entry-point validation for the user-exec tool — the function that runs an arbitrary shell command approved by the user. It guards against invoking a shell with an undefined/empty command before any process spawning or logging occurs.
Source
Thrown at src/main/skills/user-exec-runner.ts:66
const activeUserExecCommands = new Map<string, ActiveUserExecCommand>()
function getUserExecKey(sessionId: string | undefined, toolCallId: string | undefined): string | null {
return toolCallId ? `${sessionId ?? ''}:${toolCallId}` : null
}
export function cancelUserExecCommand(params: Pick<UserExecParams, 'sessionId' | 'toolCallId'>): { killed: boolean } {
const key = getUserExecKey(params.sessionId, params.toolCallId)
const active = key ? activeUserExecCommands.get(key) : undefined
if (!active) return { killed: false }
active.cancel()
return { killed: true }
}
export async function executeUserExecCommand(params: UserExecParams): Promise<UserExecResult> {
const { command, cwd: requestedCwd, timeout, sessionId, toolCallId, approvalSource } = params
try {
if (!command || typeof command !== 'string') throw new Error('Command is required')
const homeDir = os.homedir()
const cwd = requestedCwd?.trim() || homeDir
const timeoutMs = timeout || 120_000
const maxOutputBytes = 1024 * 1024 // 1MB
const operationId = createOperationId()
const startedAt = Date.now()
log.info(
buildOperationStartLog({
operationId,
kind: 'user_exec',
sessionId,
toolCallId,
// Renderer approval metadata is audit-only. Missing values remain visible
// instead of silently looking like a known authorization path.
approvalSource: approvalSource ?? 'unknown',
cwd,View on GitHub (pinned to 81571269ad)
Solutions
- Validate the command field in the tool-call argument schema (zod/string) before reaching executeUserExecCommand.
- If the model sends an empty command, treat it as a no-op tool result rather than an error.
- Ensure the tool-call deserializer preserves command as a required string field.
Example fix
// before
if (!command || typeof command !== 'string') throw new Error('Command is required')
// after — reject earlier with the tool-call schema so the runner never sees a bad payload
const UserExecArgsSchema = z.object({ command: z.string().min(1), cwd: z.string().optional(), timeout: z.number().optional() })
const parsed = UserExecArgsSchema.parse(params)
// executeUserExecCommand then assumes a valid command Defensive patterns
Strategy: validation
Validate before calling
import { z } from 'zod'
const UserExecArgsSchema = z.object({
command: z.string().min(1),
cwd: z.string().optional(),
timeout: z.number().int().positive().max(600000).optional(),
sessionId: z.string().optional(),
toolCallId: z.string().optional(),
})
const parsed = UserExecArgsSchema.parse(params)
// pass parsed to executeUserExecCommand Type guard
function isUserExecParams(p: unknown): p is { command: string } {
return typeof (p as any)?.command === 'string' && ((p as any).command as string).length > 0
} Try / catch
// executeUserExecCommand returns a UserExecResult envelope; catch for the validation path only.
try {
const result = await executeUserExecCommand(params)
if (!result.success) reportError(result.stderr)
} catch (e) {
if (e instanceof Error && /Command is required/i.test(e.message)) {
showToast('A command is required')
} else throw e
} Prevention
- Validate the tool-call arguments with a schema before they reach the runner.
- Treat an empty command as a no-op tool result rather than a thrown error.
- Ensure the tool-call deserializer marks command as required.
When it happens
Trigger: The LLM tool-call payload omits command, passes an empty string, or passes a non-string (number, object, null). executeUserExecCommand destructures command from params and immediately checks `!command || typeof command !== 'string'`.
Common situations: The model emits a tool call with command: null or command: '' because it reasoned about an empty action; a deserialization bug in the tool-call argument parser drops the field; a test fixture constructs UserExecParams without command. The approval flow (approvalSource) runs regardless, but the command itself must be a non-empty string.
Related errors
- Skill name and script name are required
- No readable text content found in EPUB file
- Embedding batch failed: expected ${batchTexts.length}, got $
- Knowledge base name is required
- No authorization code found in the input
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/f07d6949b40e8553.
Report an issue: GitHub.