google/zx · error · Fail
Failed to fetch remote script
Error message
Failed to fetch remote script: ${remote} (${res.status}) What it means
Thrown by readScriptFromHttp() when `zx <http(s) url>` gets a non-2xx response. zx fetches the URL with the global fetch() and rejects on !res.ok, embedding the HTTP status code in the message and setting exitCode to 1.
Solutions
- Verify the URL independently: `curl -iL <url>` and check the status.
- Use the raw URL for gists/repos (e.g. `https://raw.githubusercontent.com/...`).
- Add authentication (token in the URL or a custom fetch via a wrapper) if the resource is private.
- Download the file and run it locally instead: `curl -o s.mjs <url> && zx s.mjs`.
- Retry; if flaky, wrap the zx invocation in a retry or check connectivity/proxy.
Example fix
// before: gist HTML page is not the script $ zx https://gist.github.com/user/abc123 // after: use the raw endpoint $ zx https://raw.githubusercontent.com/gist/abc123/raw/script.mjs
Defensive patterns
Strategy: retry
Validate before calling
async function headOk(url: string): Promise<boolean> {
const res = await fetch(url, { method: 'HEAD' })
return res.ok
}
if (!(await headOk(scriptUrl))) {
throw new Error(`remote script unreachable: ${scriptUrl}`)
} Try / catch
try {
await runRemote(scriptUrl)
} catch (e) {
if (e instanceof Fail && /Failed to fetch remote script/.test(e.message)) {
// fall back: download then run locally
await $`curl -fsSL ${scriptUrl} -o /tmp/s.mjs`
await $`zx /tmp/s.mjs`
} else throw e
} Prevention
- Verify remote URLs with curl -iL before wiring them into zx invocations.
- Pin to raw content URLs (raw.githubusercontent.com) for gists and repo files.
- Cache remote scripts locally for offline/retry resilience instead of fetching on every run.
When it happens
Trigger: `zx https://example.com/script.mjs` where the server returns 404/403/500; a gist URL that is not the raw endpoint (HTML page, non-2xx); a private repo/gist requiring auth; corporate proxy returning a block page (403).
Common situations: Wrong or mistyped URL; deleted/moved remote script; auth required; corporate proxy/VPN interfering; transient server outage.
Related errors
AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13).
Data as JSON: /api/errors/b8c805003627d6f9.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli.ts:256
if (ext === '.md') {
script = transformMarkdown(script)
tempPath = getFilepath(dir, base, EXT)
}
if (argSlice) updateArgv(argv._.slice(argSlice))
return { script, scriptPath, tempPath }
}
async function readScriptFromStdin(): Promise<string> {
return process.stdin.isTTY ? '' : stdin()
}
async function readScriptFromHttp(remote: string): Promise<string> {
const res = await fetch(remote)
if (!res.ok) {
console.error(`Error: Can't get ${remote}`)
process.exitCode = 1
throw new Fail(`Failed to fetch remote script: ${remote} (${res.status})`)
}
return res.text()
}
export function injectGlobalRequire(origin: string): void {
const __filename = path.resolve(origin)
const __dirname = path.dirname(__filename)
const require = createRequire(origin)
Object.assign(globalThis, { __filename, __dirname, require })
}
export function isMain(
meta: ImportMeta['url'] | ImportMeta = import.meta.url,
scriptpath: string = process.argv[1]
): boolean {
if (typeof meta === 'string') {
if (meta.startsWith('file:')) {
const modulePath = url.fileURLToPath(meta).replace(/\.\w+$/, '')View on GitHub (pinned to 00a2c484e2)