mastra-ai/mastra · error · Error
Refusing to pass unsafe argument to shell command: ${JSON.st
Error message
Refusing to pass unsafe argument to shell command: ${JSON.stringify(arg)} What it means
createChildProcessLogger spawns child processes with shell:true, which makes each argument a shell-injection risk. Before spawning it validates every arg against SAFE_SHELL_ARG and throws if an argument contains characters outside the safe set. The error names the rejected argument via JSON.stringify so it is visible even if it contains quotes or control characters.
Source
Thrown at packages/deployer/src/deploy/log.ts:36
},
});
};
/**
* Args are joined into a shell command (`shell: true` is required for package
* manager shims on Windows), so only allow characters that appear in package
* specifiers and CLI flags — never shell metacharacters (CodeQL
* js/shell-command-constructed-from-input).
*/
const SAFE_SHELL_ARG = /^[\w@%+=:,./^~-]*$/;
export function createChildProcessLogger({ logger, root }: { logger: IMastraLogger; root: string }) {
const pinoStream = createPinoStream(logger);
return async ({ cmd, args, env }: { cmd: string; args: string[]; env: Record<string, string> }) => {
try {
for (const arg of args) {
if (!SAFE_SHELL_ARG.test(arg)) {
throw new Error(`Refusing to pass unsafe argument to shell command: ${JSON.stringify(arg)}`);
}
}
const subprocess = spawn(cmd, args, {
cwd: root,
shell: true,
env,
// No stdin for the child process — it doesn't need interactive input
stdio: ['ignore', 'pipe', 'pipe'],
});
let stdout = '';
let stderr = '';
subprocess.stdout?.on('data', chunk => {
stdout += chunk.toString();
});
subprocess.stderr?.on('data', chunk => {
stderr += chunk.toString();
});View on GitHub (pinned to 75dd419e61)
Solutions
- Remove/escape unsafe characters from the offending argument (rename directories to avoid spaces or shell metacharacters).
- Ensure arguments are passed as separate array items, not as one pre-joined command string.
- Sanitize or validate dynamic values (paths, names) before invoking deployer commands that spawn child processes.
Example fix
// before
spawn('pnpm', ['install --prefer-offline'], { shell: true })
// after
spawn('pnpm', ['install', '--prefer-offline'], { shell: true }) Defensive patterns
Strategy: validation
Validate before calling
const SAFE_SHELL_ARG = /^[A-Za-z0-9_@%+=:,./-]+$/;
args.forEach(arg => { if (!SAFE_SHELL_ARG.test(arg)) throw new Error(`Unsafe shell arg: ${JSON.stringify(arg)}`); }); Try / catch
try {
await runCommand({ cmd, args, env });
} catch (e) {
if (String(e.message).startsWith('Refusing to pass unsafe argument')) {
console.error('Sanitize args (no spaces/quotes/metacharacters) before retrying.');
}
throw e;
} Prevention
- Pass arguments as separate array elements, never a pre-joined command string
- Avoid spaces and shell metacharacters in project paths and names
- Sanitize env/CI-derived values before passing them as command args
When it happens
Trigger: Running a command (install/build/start) where any element of args contains characters disallowed by SAFE_SHELL_ARG — typically spaces, quotes, semicolons, backticks, $, or newline characters — passed through createChildProcessLogger.
Common situations: File paths with spaces on Windows/macOS; project names or env-derived values with special characters; a package name or directory interpolated into an arg from user input or CI variables.
Related errors
- Extractor metadataKeyPath "${keyPath}" contains an unsafe pa
- Cookie password must be at least 32 characters for SSO. Set
- [MastraAuthGoogle] GOOGLE_COOKIE_PASSWORD is required for Go
- Invalid Google ID token nonce
- Cookie password must be at least 32 characters. Set OKTA_COO
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f1677f09750c43d6.
Report an issue: GitHub.