affaan-m/ECC · error · Error
Script name must be a non-empty string
Error message
Script name must be a non-empty string
What it means
Thrown by getRunCommand() in scripts/lib/package-manager.js when the `script` argument is falsy or not a string. getRunCommand maps a script name (dev/build/test/install or arbitrary) to the detected package manager's run command; this is the first of two guards that prevent shell-metacharacter injection by validating input shape before the command string is built.
Source
Thrown at scripts/lib/package-manager.js:298
} catch (err) {
throw new Error(`Failed to save package manager config to ${configPath}: ${err.message}`);
}
return config;
}
// Allowed characters in script/binary names: alphanumeric, dash, underscore, dot, slash, @
// This prevents shell metacharacter injection while allowing scoped packages (e.g., @scope/pkg)
const SAFE_NAME_REGEX = /^[@a-zA-Z0-9_./-]+$/;
/**
* Get the command to run a script
* @param {string} script - Script name (e.g., "dev", "build", "test")
* @param {object} options - { projectDir }
* @throws {Error} If script name contains unsafe characters
*/
function getRunCommand(script, options = {}) {
if (!script || typeof script !== 'string') {
throw new Error('Script name must be a non-empty string');
}
if (!SAFE_NAME_REGEX.test(script)) {
throw new Error(`Script name contains unsafe characters: ${script}`);
}
const pm = getPackageManager(options);
switch (script) {
case 'install':
return pm.config.installCmd;
case 'test':
return pm.config.testCmd;
case 'build':
return pm.config.buildCmd;
case 'dev':
return pm.config.devCmd;
default:
return `${pm.config.runCmd} ${script}`;View on GitHub (pinned to 01e15490f0)
Solutions
- Pass a literal known script name: getRunCommand('test', { projectDir }).
- If the script name is dynamic, default-coalesce first: getRunCommand(scriptName || 'build', options).
- Validate the upstream source supplies a non-empty string before calling (e.g. guard on typeof + length).
- If the input is genuinely optional, branch on its presence and skip the call rather than passing undefined.
Example fix
// before
const cmd = getRunCommand(userScript, opts); // userScript is undefined
// after
if (!userScript || typeof userScript !== 'string') {
throw new Error('A script name is required');
}
const cmd = getRunCommand(userScript, opts); Defensive patterns
Strategy: type-guard
Validate before calling
if (!script || typeof script !== 'string') {
throw new Error('script name is required');
}
const cmd = getRunCommand(script, opts); Type guard
function isScriptName(value) {
return typeof value === 'string' && value.length > 0;
} Prevention
- Always pass a literal or explicitly validated script name.
- Default-coalesce optional inputs: script || 'build'.
- Keep flags out of the script name; append them after the call.
When it happens
Trigger: Calling getRunCommand() with no arguments, getRunCommand(undefined), getRunCommand(''), getRunCommand(null), or getRunCommand(123). Any caller that reads the script name from an untrusted or optional source (CLI flag, config file, object property) and forwards it without a type check hits this.
Common situations: Refactoring a caller so the script variable is conditionally assigned and becomes undefined; reading a script name from a JSON config that omits the key; a wrapper that defaults args to undefined instead of a real script name; test fixtures that pass nothing.
Related errors
- Binary name must be a non-empty string
- Unknown package manager: ${pmName}
- Script name contains unsafe characters: ${script}
- Binary name contains unsafe characters: ${binary}
- Arguments contain unsafe characters: ${args}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/3072b6badd2c1a88.
Report an issue: GitHub.