affaan-m/ECC · error

Binary name contains unsafe characters

Error message

Binary name contains unsafe characters: ${binary}

What it means

getExecCommand() validates the binary name against SAFE_NAME_REGEX before building the shell command. This error is thrown when the binary is a proper non-empty string but contains characters outside the safe allowlist (spaces, '/', path separators in some forms, quotes, ';', '$()', etc.). It exists to stop untrusted binary names from injecting shell commands.

Solutions

  1. Pass only the bare binary token ('prettier', 'eslint') and move arguments to the args parameter (validated separately).
  2. Remove shell metacharacters from the value; check the offending name in the error message.
  3. If you need a specific binary path, use an API that accepts an absolute path or executable directly rather than embedding flags/paths with spaces here.
  4. Sanitize at the boundary: validate tool names from config/user input with the same allowlist before calling.

Example fix

// before
getExecCommand(`node ${scriptPath} --fix`)
// after
getExecCommand('node', `${scriptPath} --fix`) // args validated by SAFE_ARGS_REGEX
Defensive patterns

Strategy: validation

Validate before calling

const SAFE_BINARY = /^[A-Za-z0-9._-]+$/;
if (!SAFE_BINARY.test(binary)) {
  throw new Error(`Unsafe binary name: ${binary}`);
}
getExecCommand(binary, args);

Type guard

function isSafeBinaryName(v) {
  return typeof v === 'string' && /^[A-Za-z0-9._-]+$/.test(v);
}

Try / catch

try {
  const cmd = getExecCommand(binary, args);
} catch (e) {
  if (String(e.message).startsWith('Binary name contains unsafe characters')) {
    console.error(`Split '${binary}' into a bare binary plus args before calling.`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling getExecCommand with a binary value containing metacharacters or whitespace: getExecCommand('prettier --write'), getExecCommand('node -e x'), getExecCommand('/usr/bin/tool; rm -rf /'), getExecCommand('tool`id`').

Common situations: Concatenating a binary name with its arguments into one string; putting a full path with spaces into the binary slot; forwarding user-controlled input (CLI arg, config) as the binary; attempting to run inline scripts via 'node -e' or 'sh -c' through this API instead of a dedicated spawn API.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/7431f17f769da684. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/package-manager.js:335

  }
}

// Allowed characters in arguments: alphanumeric, whitespace, dashes, dots, slashes,
// equals, colons, commas, quotes, @. Rejects shell metacharacters like ; | & ` $ ( ) { } < > !
const SAFE_ARGS_REGEX = /^[@a-zA-Z0-9\s_./:=,'"*+-]+$/;

/**
 * Get the command to execute a package binary
 * @param {string} binary - Binary name (e.g., "prettier", "eslint")
 * @param {string} args - Arguments to pass
 * @throws {Error} If binary name or args contain unsafe characters
 */
function getExecCommand(binary, args = '', options = {}) {
  if (!binary || typeof binary !== 'string') {
    throw new Error('Binary name must be a non-empty string');
  }
  if (!SAFE_NAME_REGEX.test(binary)) {
    throw new Error(`Binary name contains unsafe characters: ${binary}`);
  }
  if (args && typeof args === 'string' && !SAFE_ARGS_REGEX.test(args)) {
    throw new Error(`Arguments contain unsafe characters: ${args}`);
  }

  const pm = getPackageManager(options);
  return `${pm.config.execCmd} ${binary}${args ? ' ' + args : ''}`;
}

/**
 * Interactive prompt for package manager selection
 * Returns a message for Claude to show to user
 *
 * NOTE: Does NOT spawn child processes to check availability.
 * Lists all supported PMs and shows how to configure preference.
 */
function getSelectionPrompt() {
  let message = '[PackageManager] No package manager preference detected.\n';

View on GitHub (pinned to 8321021c54)