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

  1. Pass a script file path: `zx script.mjs`.
  2. Use --eval / -e to provide inline code: `zx -e "console.log('hi')"`.
  3. Pipe actual script content: `cat script.mjs | zx`.
  4. 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

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


AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13). Data as JSON: /api/errors/cb5eb36916cf17cc. Report an issue: GitHub.