google/zx · error · Fail
No script provided
Error message
No script provided
What it means
Thrown by readScript() in the zx CLI when no script source could be obtained: no positional file argument, no --eval, no http(s) URL, and stdin produced zero bytes (or is a TTY). zx needs a script to run, so after printing usage it exits with code 1.
Source
Thrown at src/cli.ts:221
async function readScript() {
const [firstArg] = argv._
let script = ''
let scriptPath = ''
let tempPath = ''
let argSlice = 1
if (argv.eval) {
argSlice = 0
script = argv.eval
tempPath = getFilepath($.cwd, 'zx', argv.ext)
} else if (!firstArg || firstArg === '-') {
script = await readScriptFromStdin()
tempPath = getFilepath($.cwd, 'zx', argv.ext)
if (script.length === 0) {
printUsage()
process.exitCode = 1
throw new Fail('No script provided')
}
} else if (/^https?:/.test(firstArg)) {
const { name, ext = argv.ext } = path.parse(new URL(firstArg).pathname)
script = await readScriptFromHttp(firstArg)
tempPath = getFilepath($.cwd, name, ext)
} else {
script = await fs.readFile(firstArg, 'utf8')
scriptPath = firstArg.startsWith('file:')
? url.fileURLToPath(firstArg)
: path.resolve(firstArg)
}
const { ext, base, dir } = path.parse(tempPath || scriptPath)
if (ext === '' || (argv.ext && !EXT_RE.test(ext))) {
tempPath = getFilepath(dir, base)
}
if (ext === '.md') {
script = transformMarkdown(script)View on GitHub (pinned to 00a2c484e2)
Solutions
- Pass a script file path: `zx script.mjs`.
- Use --eval / -e to provide inline code: `zx -e "console.log('hi')"`.
- Pipe actual script content: `cat script.mjs | zx`.
- Fetch from a URL: `zx https://example.com/script.mjs`.
Example fix
// before $ zx // after $ zx ./build.mjs
Defensive patterns
Strategy: validation
Validate before calling
function resolveScriptSource(argv, isTTY: boolean): 'file' | 'eval' | 'url' | 'stdin' | null {
if (argv.eval) return 'eval'
const [first] = argv._
if (first && /^https?:/.test(first)) return 'url'
if (first && first !== '-') return 'file'
if (!isTTY) return 'stdin'
return null // nothing to read -> would throw 'No script provided'
}
if (resolveScriptSource(argv, process.stdin.isTTY!) === null) {
printUsage(); process.exit(1)
} Try / catch
try {
await main()
} catch (e) {
if (e instanceof Fail && /No script provided/.test(e.message)) {
console.error('Pass a file, -e <code>, a URL, or pipe a script via stdin.')
process.exitCode = 1
} else throw e
} Prevention
- Always pass an explicit script path or -e expression in CI.
- When piping, assert the stream is non-empty before invoking zx.
- Treat an interactive TTY with no args as a usage error at the wrapper level.
When it happens
Trigger: Invoking `zx` with no arguments in an interactive terminal (stdin is a TTY); `echo -n '' | zx` or piping an empty stream; `zx -` with empty stdin; a CI job that forgot to pass the script path.
Common situations: Forgetting the script path; misconfigured shell pipe that sends no data; wrapper script that conditionally drops the file argument; Docker ENTRYPOINT missing the script.
Related errors
- Can't link node_modules: ${target} doesn't exist or is not a
- Can't link node_modules: ${alias} already exists
- Failed to fetch remote script: ${remote} (${res.status})
AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13).
Data as JSON: /api/errors/cb5eb36916cf17cc.
Report an issue: GitHub.